from django.db import connection
from rest_framework import serializers
from rest_framework.exceptions import ValidationError, bad_request
from django.utils.timezone import localtime
from . import models as dec_models
from . import utils
from . import fetch_data as dec_fetch_data
from rest_framework import status
from datetime import date
from po_app import models as po_models



class ReferenceField(serializers.CharField):
    """Encoded ID field for related models."""

    def __init__(self, serializer=None, related_model=None, *args, **kwargs):
        """Initialize field with an optional serializer and related model."""
        self.serializer = serializer
        self.related_model = related_model
        super().__init__(*args, **kwargs)

    def to_representation(self, value):
        """Convert the value to a serialized object or ID."""
        if not value:
            return None
        if self.serializer:
            return self.serializer(value).data
        return getattr(value, "id", value) if isinstance(value, int) else value.id

    def to_internal_value(self, value):
        """Convert the incoming value into a model instance."""
        if self.related_model and isinstance(value, self.related_model):
            return value

        try:
            value = int(value)
        except (TypeError, ValueError):
            raise serializers.ValidationError("Invalid ID format.")

        related_model = self.related_model or self._get_related_model()
        if not related_model:
            raise serializers.ValidationError("Invalid field. Ensure the key matches the model field.")

        try:
            return related_model.objects.get(id=value)
        except related_model.DoesNotExist:
            raise serializers.ValidationError("Invalid ID - object does not exist.")

    def _get_related_model(self):
        """Dynamically fetch related model if not explicitly provided."""
        try:
            return self.parent.Meta.model._meta.get_field(self.source).related_model
        except AttributeError:
            return None



class CustomModelSerializer(serializers.ModelSerializer):

    remarks = serializers.CharField(
        required=False, allow_null=True, allow_blank=True)

    def to_representation(self, instance):
        # Get the default representation
        representation = super().to_representation(instance)

        # Format the created_on field
        if instance.created_on:
            representation['created_on'] = localtime(instance.created_on).strftime('%Y-%m-%d - %I:%M %p') if instance.created_on else None
        if instance.updated_on:
            representation['updated_on'] = localtime(instance.updated_on).strftime('%Y-%m-%d') if instance.updated_on else None
        if instance.deleted_on:
            representation['deleted_on'] = localtime(instance.deleted_on).strftime('%Y-%m-%d') if instance.deleted_on else None
        return representation

    def is_valid(self, raise_exception=False):
        valid = super().is_valid(raise_exception=False)
        if not valid:
            errors = {
                "status": "failure",
                "status_code": "VALIDATION_ERROR",
                "Remarks": "Invalid data",
                "result": [self.errors],
            }
            if raise_exception:
                raise ValidationError(errors)
        return valid

    def update(self, instance, validated_data):
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        return instance
    
class BaseCompanySerializer(serializers.ModelSerializer):
    """Serializer for basic company details"""

    class Meta:
        model = dec_models.Company
        fields = '__all__'

    


class CompanySerializer(serializers.ModelSerializer):
    """Serializer for company details for eud declarations"""

    expires_in = serializers.SerializerMethodField(
        required=False, read_only=True)
    expires_on = serializers.SerializerMethodField(
        required=False, read_only=True)


    class Meta:
        model = dec_models.Company
        fields = '__all__'

    def to_representation(self, instance):
        """ Override representation function to format response data"""
        representation = super().to_representation(instance)

        expires_on = instance.latest_expiry
        today = date.today()
        in_next_14_days = False
        if expires_on:
            days_left = (expires_on - today).days
            in_next_14_days = True if 0<days_left<=14 else False
        representation['in_next_14_days'] = in_next_14_days

        return representation

    def get_expires_in(self, instance):
        """Return number of days until expiry"""

        today = date.today()
        declarations = instance.declarations.filter(is_deleted=False).order_by('expiry_date')
        if not declarations:
            instance.latest_expiry = None
            instance.save()
            return None

        expires_on = declarations[0].expiry_date
        days_left = (expires_on - today).days
        instance.latest_expiry = expires_on
        instance.save()

        if days_left < 0:
            return f"Expired {-days_left} days ago"
        elif days_left == 0:
            return "Expires today"
        else:
            return f"{days_left} days left"

    def get_expires_on(self, instance):
        """Return the active document file path for the declaration"""
        declarations = instance.declarations.filter(is_deleted=False).order_by('expiry_date')
        if declarations:
            expires_on = declarations[0].expiry_date.strftime('%d-%m-%Y')
        else:
            expires_on = None
        return expires_on


class EUDeclarationSerializer(serializers.ModelSerializer):
    """Serializer for Eud declarations"""
    company = ReferenceField(related_model=dec_models.Company, required=False)
    document_id = serializers.CharField(write_only=True, required=False)
    file = serializers.FileField(required=False, allow_null=True, write_only=True)
    document = serializers.SerializerMethodField(
        required=False, read_only=True)
    expires_in = serializers.SerializerMethodField(
        required=False, read_only=True)
    requested_by = serializers.SerializerMethodField(
        required=False, read_only=True)
    requested_on = serializers.SerializerMethodField(
        required=False, read_only=True)

    class Meta:
        model = dec_models.EUDeclaration
        exclude = ['updated_by', 'deleted_by', 'created_on', 'updated_on', 'deleted_on']

    def to_representation(self, instance):
        """ Override representation function to format response data"""
        representation = super().to_representation(instance)

        representation['expiry_date'] = instance.expiry_date.strftime('%d-%m-%Y')
        representation['status'] = instance.get_declaration_status()

        return representation

    def create(self, validated_data):
        """ function to override create serializer"""
        company = validated_data['company']
        file=None
        if 'file' in validated_data.keys():
            file = validated_data.pop('file', None)

        try:
            declaration, created = self.Meta.model.objects.get_or_create(
                company=company, product_name=validated_data['product_name'],
                start_date=validated_data['start_date'])
        except Exception as e:
            message = f"Unexpected error: {str(e)}"
            raise ValidationError(
                {
                    'message': f'Unexpected error while creating declaration: {str(e)}',
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'status': "error",
                    'data': None,
            })

        if file:
            declaration = utils.manage_declaration_files(file, declaration)

        declaration_data = super().update(declaration, validated_data)
        return declaration_data

    def update(self, instance, validated_data):
        """function to update declaration"""
        if 'file' in validated_data.keys():
            file = validated_data.pop('file', None)
            declaration = utils.manage_declaration_files(file, instance)
        declaration_data = super().update(instance, validated_data)
        return declaration_data

    def get_document(self, instance):
        """Return the active document file path for the declaration"""
        if instance.document_id:
            try:
                document = dec_models.DeclarationDocument.objects.get(id=instance.document_id)
                if document.file_path:
                    return document.file_path.url
            except dec_models.DeclarationDocument.DoesNotExist:
                return None
        return None

    def get_expires_in(self, instance):
        """Return number of days until expiry"""
        if not instance.expiry_date:
            return None

        today = date.today()
        days_left = (instance.expiry_date - today).days

        if days_left < 0:
            return f"Expired {-days_left} days ago"
        elif days_left == 0:
            return "Expires today"
        else:
            return f"{days_left} days left"
        
    def get_requested_by(self, instance):
        """Return name of user who has sent the renewal request"""
        declaration_history = instance.declaration_histories.first()
        if declaration_history:
            user_id = declaration_history.request_sent_by
            query = f"""
                    SELECT Username FROM UserMaster Where Id={user_id}
                """
                # Execute the query directly
        
            with connection.cursor() as cursor:
                cursor.execute(query)
                result = cursor.fetchone()
            username = result[0] if result else None
            return username
        else:
            return None
        
    def get_requested_on(self, instance):
        """Return name of user who has sent the renewal request"""
        declaration_history = instance.declaration_histories.first()
        if declaration_history:
            requested_on = declaration_history.requested_on
            return requested_on.strftime('%d/%m/%Y %I:%M %p')
        else:
            return None
            
            
class SharedDocumentSerializer(serializers.ModelSerializer):
    """Serializer for Eud declarations"""
    company = ReferenceField(related_model=dec_models.Company, required=False)
    # file_path = serializers.FileField(required=False, allow_null=True, write_only=True)
    shared_to = serializers.SerializerMethodField(
        required=False, read_only=True)

    class Meta:
        model = dec_models.SharedDocument
        exclude = ['updated_by', 'deleted_by', 'created_on', 'updated_on', 'deleted_on']

    def to_representation(self, instance):
        """ Override representation function to format response data"""
        representation = super().to_representation(instance)
        representation['shared_on'] = instance.shared_on.strftime('%d-%m-%Y %I:%M %p')

        user_data = dec_fetch_data.get_user_data(representation['shared_by'])
        full_name = user_data.get('full_name', '')
        representation['shared_by'] = full_name

        shared_to = representation.pop('shared_to')

        representation['to_mails'] = shared_to.get('to', '')
        representation['cc_mails'] = shared_to.get('cc', '')

        return representation
    
    def get_shared_to(self, instance):
        """Return mails ids whose the files are shared to"""
        email_logs = po_models.EmailLog.objects.filter(receipient_id=instance.id).last()

        if email_logs:
            to = email_logs.recipient
            cc = email_logs.cc
        else:
            to = cc = ''

        return {'to': to, 'cc': cc}
    

class SavedDocumentSerializer(serializers.ModelSerializer):
    """Serializer for Eud declarations"""
    company = ReferenceField(related_model=dec_models.Company, required=False)
    # file_path = serializers.FileField(required=False, allow_null=True, write_only=True)

    class Meta:
        model = dec_models.SavedDocument
        fields = '__all__' 

    def to_representation(self, instance):
        """ Override representation function to format response data"""
        representation = super().to_representation(instance)
        representation['created_on'] = instance.created_on.strftime('%d-%m-%Y %I:%M %p')

        user_data = dec_fetch_data.get_user_data(representation['created_by'])
        full_name = user_data.get('full_name', '')
        representation['created_by'] = full_name

        return representation

