"""This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license."""

from core.label_config import replace_task_data_undefined_with_config_field
from core.utils.common import load_func
from data_export.models import DataExport
from django.conf import settings
from fsm.serializer_fields import FSMStateField
from label_studio_sdk._extensions.label_studio_tools.core.label_config import is_video_object_tracking
from label_studio_sdk._extensions.label_studio_tools.postprocessing.video import extract_key_frames
from ml.mixins import InteractiveMixin
from rest_flex_fields import FlexFieldsModelSerializer
from rest_framework import serializers
from tasks.models import Annotation, Task
from tasks.serializers import AnnotationDraftSerializer, PredictionSerializer
from users.models import User
from users.serializers import UserSimpleSerializer

from .models import ConvertedFormat, Export


class CompletedBySerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'email', 'first_name', 'last_name']


class AnnotationSerializer(FlexFieldsModelSerializer):
    completed_by = serializers.PrimaryKeyRelatedField(read_only=True)
    result = serializers.SerializerMethodField()
    state = FSMStateField(read_only=True)  # FSM state for annotations

    class Meta:
        model = Annotation
        fields = '__all__'
        expandable_fields = {'completed_by': (CompletedBySerializer,)}

    def to_representation(self, instance):
        """Override to conditionally exclude FSM state field when feature flags are disabled."""
        from core.current_request import CurrentContext
        from core.feature_flags import flag_set

        ret = super().to_representation(instance)

        # Remove state field from output if either feature flag is disabled
        user = CurrentContext.get_user()
        if not (
            flag_set('fflag_feat_fit_568_finite_state_management', user=user)
            and flag_set('fflag_feat_fit_710_fsm_state_fields', user=user)
        ):
            ret.pop('state', None)

        return ret

    def get_result(self, obj):
        # run frames extraction on param, result and result type
        if (
            obj.result
            and self.context.get('interpolate_key_frames', False)
            and is_video_object_tracking(parsed_config=obj.project.get_parsed_config())
        ):
            return extract_key_frames(obj.result)
        return obj.result


class BaseExportDataSerializer(FlexFieldsModelSerializer):
    annotations = AnnotationSerializer(many=True, read_only=True)
    file_upload = serializers.ReadOnlyField(source='file_upload_name')
    drafts = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    predictions = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    state = FSMStateField(read_only=True)  # FSM state for tasks

    # resolve $undefined$ key in task data, if any
    def to_representation(self, task):
        from core.current_request import CurrentContext
        from core.feature_flags import flag_set

        # avoid long project initializations
        project = getattr(self, '_project', None)
        if project is None:
            project = task.project
            setattr(self, '_project', project)

        data = task.data
        # add interpolate_key_frames param to annotations serializer
        if 'annotations' in self.fields:
            self.fields['annotations'].context['interpolate_key_frames'] = self.context.get(
                'interpolate_key_frames', False
            )
        replace_task_data_undefined_with_config_field(data, project)

        ret = super().to_representation(task)

        # Remove state field from output if either feature flag is disabled
        user = CurrentContext.get_user()
        if not (
            flag_set('fflag_feat_fit_568_finite_state_management', user=user)
            and flag_set('fflag_feat_fit_710_fsm_state_fields', user=user)
        ):
            ret.pop('state', None)

        return ret

    class Meta:
        model = Task
        exclude = ('overlap', 'is_labeled', 'precomputed_agreement')
        expandable_fields = {
            'drafts': (AnnotationDraftSerializer, {'many': True}),
            'predictions': (PredictionSerializer, {'many': True}),
            'annotations': (AnnotationSerializer, {'many': True}),
        }


class ConvertedFormatSerializer(serializers.ModelSerializer):
    class Meta:
        model = ConvertedFormat
        fields = ['id', 'status', 'export_type', 'traceback']

    def to_representation(self, instance):
        from django.conf import settings

        data = super().to_representation(instance)

        if not getattr(settings, 'SHOW_TRACEBACK_FOR_EXPORT_CONVERTER', True):
            # Remove traceback field from output if setting is disabled
            data.pop('traceback', None)

        return data


class ExportSerializer(serializers.ModelSerializer):
    class Meta:
        model = Export
        read_only = [
            'id',
            'created_by',
            'created_at',
            'finished_at',
            'status',
            'md5',
            'counters',
            'converted_formats',
        ]
        fields = ['title'] + read_only

    created_by = UserSimpleSerializer(required=False)
    converted_formats = ConvertedFormatSerializer(many=True, required=False)


ONLY_OR_EXCLUDE_CHOICE = [
    2 * ['only'],
    2 * ['exclude'],
    2 * [None],
]


class TaskFilterOptionsSerializer(serializers.Serializer):
    view = serializers.IntegerField(
        required=False, help_text='Apply filters from the view ID (a tab from the Data Manager)'
    )
    skipped = serializers.ChoiceField(
        choices=ONLY_OR_EXCLUDE_CHOICE,
        allow_null=True,
        required=False,
        help_text='`only` - include all tasks with skipped annotations<br>'
        '`exclude` - exclude all tasks with skipped annotations',
    )
    finished = serializers.ChoiceField(
        choices=ONLY_OR_EXCLUDE_CHOICE,
        allow_null=True,
        required=False,
        help_text='`only` - include all finished tasks (is_labeled = true)<br>`exclude` - exclude all finished tasks',
    )
    annotated = serializers.ChoiceField(
        choices=ONLY_OR_EXCLUDE_CHOICE,
        allow_null=True,
        required=False,
        help_text='`only` - include all tasks with at least one not skipped annotation<br>'
        '`exclude` - exclude all tasks with at least one not skipped annotation',
    )
    only_with_annotations = serializers.BooleanField(default=False, required=False, help_text='')


class AnnotationFilterOptionsSerializer(serializers.Serializer):
    usual = serializers.BooleanField(
        allow_null=True, required=False, default=True, help_text='Include not skipped and not ground truth annotations'
    )
    ground_truth = serializers.BooleanField(
        allow_null=True, required=False, help_text='Include ground truth annotations'
    )
    skipped = serializers.BooleanField(allow_null=True, required=False, help_text='Include skipped annotations')


class SerializationOptionsSerializer(serializers.Serializer):
    class SerializationOption(serializers.Serializer):
        only_id = serializers.BooleanField(
            default=False, required=False, help_text='Include a full json body or IDs only'
        )

    drafts = SerializationOption(required=False, help_text='JSON dict with parameters')
    predictions = SerializationOption(required=False, help_text='JSON dict with parameters')
    include_annotation_history = serializers.BooleanField(
        default=False, help_text='Include annotation history', required=False
    )
    annotations__completed_by = SerializationOption(required=False, help_text='JSON dict with parameters')
    interpolate_key_frames = serializers.BooleanField(
        default=settings.INTERPOLATE_KEY_FRAMES, help_text='Interpolate video key frames', required=False
    )


class ExportConvertSerializer(serializers.Serializer):
    export_type = serializers.CharField(help_text='Export file format.')
    download_resources = serializers.BooleanField(help_text='Download resources in converter.', required=False)

    def validate_export_type(self, value):
        project = self.context.get('project')
        export_formats = [f['name'] for f in DataExport.get_export_formats(project)]
        if value not in export_formats:
            raise serializers.ValidationError(f'{value} is not supported export format')
        return value


class ExportCreateSerializer(ExportSerializer):
    class Meta(ExportSerializer.Meta):
        fields = ExportSerializer.Meta.fields + [
            'task_filter_options',
            'annotation_filter_options',
            'serialization_options',
        ]

    task_filter_options = TaskFilterOptionsSerializer(required=False, default=None)
    annotation_filter_options = AnnotationFilterOptionsSerializer(required=False, default=None)
    serialization_options = SerializationOptionsSerializer(required=False, default=None)


class ExportParamSerializer(serializers.Serializer):
    interpolate_key_frames = serializers.BooleanField(
        default=settings.INTERPOLATE_KEY_FRAMES, help_text='Interpolate video key frames.', required=False
    )
    download_resources = serializers.BooleanField(
        default=settings.CONVERTER_DOWNLOAD_RESOURCES, help_text='Download resources in converter.', required=False
    )
    # deprecated param to delete
    export_type = serializers.CharField(default='JSON', help_text='Export file format.', required=False)
    exportType = serializers.CharField(help_text='Export file format.', required=False)
    download_all_tasks = serializers.BooleanField(
        default=False, help_text='Download all tasks or only finished.', required=False
    )


class BaseExportDataSerializerForInteractive(InteractiveMixin, BaseExportDataSerializer):
    pass


ExportDataSerializer = load_func(settings.EXPORT_DATA_SERIALIZER)
