from django.utils import timezone
from rest_framework import serializers

from .models import IstatAuditLog, IstatCredential, IstatSyncHistory


class IstatSyncHistorySerializer(serializers.ModelSerializer):
    timestamp = serializers.SerializerMethodField()
    triggered_by = serializers.SerializerMethodField()

    class Meta:
        model = IstatSyncHistory
        fields = [
            "id",
            "status",
            "message",
            "requested_period",
            "requested_at",
            "completed_at",
            "timestamp",
            "triggered_by",
        ]

    def get_timestamp(self, obj):
        return obj.completed_at or obj.requested_at

    def get_triggered_by(self, obj):
        if not obj.triggered_by:
            return None
        return {
            "id": obj.triggered_by_id,
            "username": obj.triggered_by.username,
        }


class IstatConnectionStatusSerializer(serializers.Serializer):
    structure_id = serializers.IntegerField()
    credential_type = serializers.CharField()
    provider = serializers.CharField()
    connected = serializers.BooleanField()
    connection_status = serializers.CharField()
    username = serializers.CharField(allow_null=True)
    password_masked = serializers.CharField(allow_null=True)
    last_sync = IstatSyncHistorySerializer(allow_null=True)
    created_at = serializers.DateTimeField(allow_null=True)
    updated_at = serializers.DateTimeField(allow_null=True)


class IstatCredentialSerializer(serializers.ModelSerializer):
    credential_type = serializers.SerializerMethodField()
    provider = serializers.SerializerMethodField()
    connected = serializers.SerializerMethodField()
    connection_status = serializers.SerializerMethodField()
    username = serializers.SerializerMethodField()
    password_masked = serializers.SerializerMethodField()
    last_sync = serializers.SerializerMethodField()

    class Meta:
        model = IstatCredential
        fields = [
            "id",
            "structure_id",
            "credential_type",
            "provider",
            "connected",
            "connection_status",
            "username",
            "password_masked",
            "last_sync",
            "created_at",
            "updated_at",
        ]

    def get_credential_type(self, obj):
        return "ISTAT"

    def get_provider(self, obj):
        return "Ross1000"

    def get_connected(self, obj):
        return True

    def get_connection_status(self, obj):
        return "connected"

    def get_username(self, obj):
        return obj.username

    def get_password_masked(self, obj):
        return obj.masked_password

    def get_last_sync(self, obj):
        sync_record = obj.structure.istat_sync_history.first()
        if not sync_record:
            return None
        return IstatSyncHistorySerializer(sync_record).data


class IstatCredentialWriteSerializer(serializers.Serializer):
    username = serializers.CharField(
        max_length=255,
        trim_whitespace=True,
        required=False,
    )
    password = serializers.CharField(
        max_length=255,
        trim_whitespace=False,
        required=False,
        write_only=True,
        style={"input_type": "password"},
    )

    def validate(self, attrs):
        errors = {}

        if self.instance is None:
            for field_name in ("username", "password"):
                if not attrs.get(field_name):
                    errors[field_name] = "This field is required."

        if self.instance is not None and not attrs:
            raise serializers.ValidationError(
                "At least one field must be provided."
            )

        for field_name in ("username", "password"):
            value = attrs.get(field_name)
            if value is not None and not str(value).strip():
                errors[field_name] = "This field may not be blank."

        if errors:
            raise serializers.ValidationError(errors)

        return attrs

    def create(self, validated_data):
        structure = self.context["structure"]
        user = self.context["user"]

        credential = IstatCredential(
            structure=structure,
            created_by=user,
            updated_by=user,
        )
        credential.username = validated_data["username"]
        credential.password = validated_data["password"]
        credential.save()
        return credential

    def update(self, instance, validated_data):
        if "username" in validated_data:
            instance.username = validated_data["username"]
        if "password" in validated_data:
            instance.password = validated_data["password"]

        instance.updated_by = self.context["user"]
        instance.save()
        return instance


class IstatManualSyncRequestSerializer(serializers.Serializer):
    year = serializers.IntegerField(
        min_value=2000,
        max_value=2100,
        required=False,
    )
    month = serializers.IntegerField(min_value=1, max_value=12, required=False)

    def validate(self, attrs):
        today = timezone.localdate()

        if "month" in attrs and "year" not in attrs:
            attrs["year"] = today.year
        if "year" in attrs and "month" not in attrs:
            attrs["month"] = today.month
        if not attrs:
            attrs["year"] = today.year
            attrs["month"] = today.month

        return attrs


class IstatManualSyncResponseSerializer(serializers.Serializer):
    status = serializers.CharField()
    message = serializers.CharField()
    timestamp = serializers.DateTimeField()
    requested_period = serializers.JSONField()


class IstatAuditLogSerializer(serializers.ModelSerializer):
    actor = serializers.SerializerMethodField()

    class Meta:
        model = IstatAuditLog
        fields = [
            "id",
            "action",
            "message",
            "metadata",
            "created_at",
            "actor",
        ]

    def get_actor(self, obj):
        if not obj.actor:
            return None
        return {
            "id": obj.actor_id,
            "username": obj.actor.username,
        }
