import time
import yenv

from django.conf import settings
from django.db.models import OuterRef, Prefetch
from django.utils.functional import cached_property
from yt import wrapper as yt

from intranet.femida.src.attachments.models import Attachment
from intranet.femida.src.core.db import RowToDict
from intranet.femida.src.interviews.models import Interview
from intranet.femida.src.yt.serializers import (
    CandidateAttachmentYTSerializer,
    VerificationYTSerializer,
    OfferYTSerializer,
    InterviewRoundYTSerializer,
    ScreenshotYTSerializer,
    ScoringUploadResultSerializer,
)


class BaseYTTable:

    serializer = None
    schema = None
    table_name = None
    attributes = None

    def __init__(self, **kwargs):
        self.kwargs = kwargs
        yt.config['token'] = settings.YT_TOKEN
        yt.config['proxy']['url'] = settings.YT_PROXY

        if yenv.type == 'production':
            yt_table_path = '//home/femida/{}'
        else:
            yt_table_path = '//home/femida/test/{}'

        self.path = yt_table_path.format(self.table_name)
        if self.serializer:
            self.schema = self.serializer.Meta.yt_schema

    def serialize_data(self, qs):
        return self.serializer(qs, many=True).data

    def prefetch_related(self, qs):
        return qs

    @cached_property
    def _schema(self):
        return [{'name': k, 'type': v} for k, v in self.schema.items()]

    def read(self):
        table = yt.TablePath(self.path)
        return yt.read_table(table=table)

    def create(self):
        attributes = self.attributes or {}
        if self._schema:
            attributes['schema'] = self._schema
        yt.create(
            type='table',
            path=self.path,
            recursive=True,
            ignore_existing=True,
            attributes=attributes,
        )

    def write(self, qs, *, append=False):
        qs = self.prefetch_related(qs)
        table = yt.TablePath(self.path, append=append)
        rows = self.serialize_data(qs)
        try:
            yt.write_table(table, rows)
        except yt.YtHttpResponseError as e:
            if e.is_resolve_error():
                self.create()
                yt.write_table(table, rows)
            else:
                raise


class DailyBaseYTTable(BaseYTTable):

    def __init__(self, table_date, **kwargs):
        super(DailyBaseYTTable, self).__init__(**kwargs)
        self.path = '{}/daily/{}'.format(self.path, table_date.strftime('%Y-%m-%d'))


class AttachmentYTTable(DailyBaseYTTable):

    serializer = CandidateAttachmentYTSerializer
    table_name = 'cv'

    def prefetch_related(self, qs):
        return (
            qs
            .select_related(
                'attachment__uploader',
                'candidate',
            )
            .prefetch_related(
                'candidate__responsibles',
                'candidate__candidate_professions',
            )
        )


class VerificationYTTable(DailyBaseYTTable):

    serializer = VerificationYTSerializer
    table_name = 'offer-seo'

    def prefetch_related(self, qs):
        latest_attachment = RowToDict(
            Attachment.objects
            .filter(
                candidates__verifications=OuterRef('id'),
            )
            .values(
                'id',
                'content_type',
                'text',
                'attached_file',
            )
            .order_by('-created')[:1]
        )
        return (
            qs
            .annotate(
                attachment=latest_attachment,
            )
            .select_related(
                'created_by',
                'candidate',
                'application__vacancy__department',
            )
            .prefetch_related(
                'candidate__contacts',
            )
        )


class OfferYTTable(BaseYTTable):

    serializer = OfferYTSerializer
    table_name = 'yang/offer-data'

    def serialize_data(self, qs):
        rows = super().serialize_data(qs)
        exclude = self.kwargs.get('exclude', [])
        for field in exclude:
            for row in rows:
                row[field] = None
        return rows


class ProcessedOfferYTTable(BaseYTTable):

    table_name = 'yang/offer-processed-data'


class InterviewRoundYTTable(BaseYTTable):

    serializer = InterviewRoundYTSerializer
    table_name = 'yang/interview-round-data'

    def prefetch_related(self, qs):
        return (
            qs
            .select_related(
                'created_by',
                'office',
            )
            .prefetch_related(
                'time_slots',
                Prefetch('interviews', Interview.unsafe.order_by('id')),
                'interviews__potential_interviewers',
            )
        )


class ProcessedInterviewRoundYTTable(BaseYTTable):

    table_name = 'yang/interview-round-processed-data'


class ScreenshotYTTable(BaseYTTable):

    serializer = ScreenshotYTSerializer
    table_name = 'screenshots/input'
    attributes = {
        # https://wiki.yandex-team.ru/vanadium/batch-format/#parametrybatcha
        'tellurium.parameters': {
            'main-params': {
                'retry-count': 2,
                'max-threads': 30,  # https://wiki.yandex-team.ru/vanadium/rps/
                'abc-service': 'femida',
            },
            'window-params': {
                'view-height': 628,
                'view-width': 1200,
            },
            'browser-params': {
                'platform-type': 'desktop',
                'scripts': {
                    'is-page-ready-script': 'return window.isReadyForScreenshot();',
                },
            },
        },
        'expiration_timeout': 7 * 24 * 60 * 60 * 1000,  # TTL = 1 week
    }

    def __init__(self, **kwargs):
        self.table_name = f'{self.table_name}_{time.time()}'
        super().__init__(**kwargs)

    def write(self, qs, *, append=False):
        self.create()
        super().write(qs=qs, append=append)


class ProcessedScreenshotYTTable(BaseYTTable):

    def __init__(self, path, **kwargs):
        super().__init__(**kwargs)
        self.path = path


class ScoringUploadResultsYTTable(BaseYTTable):

    serializer = ScoringUploadResultSerializer
    table_name = 'analytics/scoring_upload_logs'
