import datetime
import difflib
import logging
import os

from statface_client import StatfaceReportConfig, DAILY_SCALE

from django.apps import apps
from django.contrib.auth import get_user_model
from django.utils import timezone
from django.utils.functional import cached_property

from intranet.femida.src.stats.utils import get_beginning_of_moscow_day


logger = logging.getLogger(__name__)

User = get_user_model()


class ReportManager:
    """
    Базовый класс для загрузки отчетов в stat.yandex-team.ru
    """
    report_name = None  # Название отчета в URL
    title = None  # Человекочитаемое название отчета
    config_name = None
    scale = DAILY_SCALE
    delta = None
    dt_format = '%Y-%m-%d'
    data_fetcher_class = None

    def __init__(self):
        self.report_path = 'Femida/regular/' + self.report_name
        if self.title is None:
            self.title = self.report_name
        else:
            self.title = '%s (%s)' % (self.title, self.report_name)

        if self.config_name is None:
            self.config_name = self.report_name + '.yaml'

    @cached_property
    def report(self):
        from intranet.femida.src.stats.statface import statface
        return statface.get_report(self.report_path)

    def _get_config_content(self):
        is_arcadia = os.getenv('IS_ARCADIA')
        prefix = 'intranet/femida/src/stats' if is_arcadia else apps.get_app_config('stats').path
        path = f'{prefix}/configs/{self.config_name}'
        if is_arcadia:
            from library.python import resource
            return resource.resfs_read(path)
        else:
            with open(path) as f:
                return f.read()

    @cached_property
    def local_config(self):
        """
        Конфиг, который должен быть
        """
        config = StatfaceReportConfig()
        config.from_yaml(self._get_config_content())
        config.title = self.title
        return config

    @property
    def remote_config(self):
        """
        Конфиг, который есть по факту в Statface.
        Если он не совпадает с local_config, значит нужно залить на Statface локальный конфиг
        с помощью методы upload_config.
        """
        return self.report.config

    @property
    def config_diff(self):
        return difflib.ndiff(
            self.local_config.to_yaml().splitlines(),
            self.remote_config.to_yaml().splitlines()
        )

    def is_config_valid(self):
        return self.local_config.is_valid

    def is_config_relevant(self):
        return self.local_config.to_yaml() == self.remote_config.to_yaml()

    def initialize(self):
        self.upload_config(overwrite=False)

    def upload_config(self, overwrite=True):
        self.report.upload_config(
            config=self.local_config,
            overwrite=overwrite,
            scale=self.scale,
        )

    def get_data_fetcher_options(self):
        return {}

    def get_data(self, fielddate=None):
        """
        Если data_fetcher_class не указан, то нужно переопределить этот метод
        """
        data_fetcher = self.data_fetcher_class(
            config=self.local_config,
            fielddate=fielddate,
            delta=self.delta,
            **self.get_data_fetcher_options()
        )
        return data_fetcher.get_data()

    def upload_data(self, fielddate=None):
        data = self.get_data(fielddate)
        if not data:
            logger.error('There is no data to upload to Statface')
            return
        self.report.upload_data(
            scale=self.scale,
            data=data,
        )
        logger.info(
            'Data for report `%s` for date `%s` was uploaded.',
            self.report_name,
            fielddate,
        )

    def bulk_upload_data(self, fielddate_from, fielddate_to=None):
        """
        # TODO: Возможно перенести эту логику в DataFetcher
        # TODO: Распараллелить
        """
        if fielddate_to is None:
            today = get_beginning_of_moscow_day(timezone.now()).replace(tzinfo=None)
            to_date = today - datetime.timedelta(days=1)
        else:
            to_date = datetime.datetime.strptime(fielddate_to, self.dt_format)

        from_date = datetime.datetime.strptime(fielddate_from, self.dt_format)

        curr_date = to_date
        while curr_date >= from_date:
            curr_fielddate = curr_date.strftime(self.dt_format)
            self.upload_data(curr_fielddate)
            curr_date -= datetime.timedelta(days=1)

    def recreate(self, fielddate):
        """
        Statface не дает изменять список измерений.
        Поэтому приходится пересоздавать новый отчет.
        """
        logger.info('Recreating report `%s` in Statface', self.report_name)
        logger.info('Stage 1: Renaming...')
        self.report._api._report_post(
            uri='move',
            data={
                'path': self.report_path + '_old_{timestamp}'.format(
                    timestamp=timezone.now().strftime('%Y%m%d%H%M%S')
                ),
            },
        )

        logger.info('Stage 2: Uploading new config...')
        self.upload_config()

        logger.info('Stage 3: Uploading data from %s...', fielddate)
        self.bulk_upload_data(fielddate)

        # TODO: Возможность сразу удалить переименованный отчет

        logger.info('Report `%s` recreated.', self.report_name)
