# customermanagement/serializers.py
from django.contrib.auth.hashers import check_password
from django.core.validators import validate_email
from django.db import transaction
from django.utils import timezone as dj_tz
from rest_framework import serializers

from core.models import AppSettings, Language
from constants.general_const import ActiveStatus
from codesofy.master_details import CustomerRegistrationSource, CustomerRegistrationStatus

from customermanagement.otp_utils import OTP_EXPIRY_MINUTES, default_expiry, generate_otp, hash_otp
from .models import Customer, EmailOTP, PasswordResetToken
from .services import hash_password
import os
from dotenv import load_dotenv
load_dotenv()

class RegisterSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True, min_length=8, max_length=12)
    mobile = serializers.CharField(max_length=20, required=False, allow_blank=True)
    first_name = serializers.CharField(max_length=256)
    last_name = serializers.CharField(max_length=256, allow_blank=True, required=False)

    language_id = serializers.CharField(required=True)
    privacy_policy_version = serializers.CharField(max_length=64)
    privacy_policy_accepted = serializers.BooleanField()

    def validate_email(self, email):
        email = email.strip().lower()
        validate_email(email)
        return email

    def validate_language_id(self, value):
        if value is None or not str(value).strip():
            raise serializers.ValidationError("LANGUAGE_REQUIRED")
        lang = Language.objects.filter(code=str(value).strip().lower()).first()
        if not lang:
            raise serializers.ValidationError("LANGUAGE_INVALID")
        return str(value).strip().lower()

    def validate(self, data):
        if not data.get("privacy_policy_accepted"):
            raise serializers.ValidationError({"privacy_policy_accepted": ["PRIVACY_POLICY_MUST_ACCEPT"]})

        version = data.get("privacy_policy_version")
        if not version or not str(version).strip():
            raise serializers.ValidationError({"privacy_policy_version": ["PRIVACY_POLICY_VERSION_REQUIRED"]})

        return data

    @transaction.atomic
    def create(self, validated):
        language_code = validated.get("language_id")
        lang = Language.objects.get(code=language_code)

        privacy_version = validated.pop("privacy_policy_version", None)
        privacy_accepted = validated.pop("privacy_policy_accepted", False)
        validated.pop("language_id", None)

        email = validated["email"].strip().lower()

        mobile_provided = "mobile" in validated
        mobile_value = (validated.get("mobile") or "").strip()

        customer = Customer.objects.filter(email__iexact=email).first()

        if customer:
            if customer.is_locked:
                raise serializers.ValidationError(
                    {"code": "AUTH_LOCKED", "errors": {"email": ["AUTH_LOCKED"]}}
                )

            # Existing customer re-register case
            if customer.is_reg_blocked:
                raise serializers.ValidationError({"code": "AUTH_BLOCKED", "errors": {"email": ["AUTH_BLOCKED"]}})

            if customer.is_email_verified:
                raise serializers.ValidationError(
                    {"code": "AUTH_EMAIL_ALREADY_REGISTERED", "errors": {"email": ["AUTH_EMAIL_ALREADY_REGISTERED"]}}
                )

            customer.first_name = validated["first_name"]
            customer.last_name = validated.get("last_name") or ""
            customer.password = hash_password(validated["password"])
            customer.registration_status = CustomerRegistrationStatus.PENDING.value
            customer.customer_status = ActiveStatus.INACTIVE.value
            customer.created_by = CustomerRegistrationSource.CUSTOMER.value

            update_fields = [
                "first_name",
                "last_name",
                "password",
                "registration_status",
                "customer_status",
                "created_by",
            ]
            if mobile_provided:
                customer.mobile = mobile_value
                update_fields.append("mobile")

            customer.save(update_fields=update_fields)

        else:
            # Fresh customer create
            kwargs = dict(
                email=email,
                first_name=validated["first_name"],
                last_name=validated.get("last_name") or "",
                password=hash_password(validated["password"]),
                mobile=mobile_value if mobile_provided else "",
                registration_status=CustomerRegistrationStatus.PENDING.value,
                customer_status=ActiveStatus.INACTIVE.value,
                created_by=CustomerRegistrationSource.CUSTOMER.value,
                is_email_verified=False,
                is_reg_blocked=False,
            )
            customer = Customer.objects.create(**kwargs)

        # Save privacy acceptance
        if privacy_version and privacy_accepted:
            customer.privacy_policy_version = str(privacy_version)
            customer.privacy_policy_accepted = True
            customer.save(update_fields=["privacy_policy_version", "privacy_policy_accepted"])

        AppSettings.objects.update_or_create(
            customer_user=customer,
            defaults={"language": lang},
        )

        EmailOTP.objects.filter(customer=customer, is_valid=True, is_utilized=False).update(
            is_valid=False,
            is_utilized=True,
        )

        # OTP creation
        if email == os.getenv("DEFAULT_USER_EMAIL"):
            plain = os.getenv("DEFAULT_OTP")  # from env
        else:
            plain = generate_otp()
        label = "Wile account Verification OTP"
        expires_at = default_expiry(OTP_EXPIRY_MINUTES)

        EmailOTP.objects.create(
            customer=customer,
            otp_code=hash_otp(plain),
            created_At=dj_tz.now(),
            expired_At=expires_at,
            is_utilized=False,
            attempts_count=0,
            is_valid=True,
        )

        return customer, plain, expires_at, label


class VerifyOTPSerializer(serializers.Serializer):
    email = serializers.EmailField()
    code = serializers.CharField(min_length=6, max_length=10)


class ResendOTPSerializer(serializers.Serializer):
    email = serializers.EmailField()


class LoginSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True)
    remember_me = serializers.BooleanField(required=False, default=False)


class ForgotPasswordSerializer(serializers.Serializer):
    email = serializers.EmailField()


class ResetPasswordSerializer(serializers.Serializer):
    token = serializers.CharField()
    password = serializers.CharField(write_only=True, min_length=8, max_length=12)


class ResetPasswordWithOtpSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True, min_length=8, max_length=12)


class PasswordChangeSerializer(serializers.Serializer):
    current_password = serializers.CharField(write_only=True,trim_whitespace=False)
    new_password = serializers.CharField(write_only=True, min_length=8,max_length=12,trim_whitespace=False)

    def validate(self, attrs):
        request = self.context.get("request")
        if not request:
            raise serializers.ValidationError({
                "code": "MISSING_CONTEXT",
                "errors": {}
            })

        user = request.user
        customer = user if isinstance(user, Customer) else getattr(user, "customer", None)
        if not customer:
            raise serializers.ValidationError({
                "code": "CUSTOMER_NOT_FOUND",
                "errors": {}
            })

        current_pw = attrs.get("current_password")
        new_pw = attrs.get("new_password")

        if not current_pw:
            raise serializers.ValidationError({
                "code": "MISSING_CURRENT_PASSWORD",
                "errors": {
                    "current_password": ["required"]
                }
            })

        if not check_password(current_pw, customer.password):
            raise serializers.ValidationError({
                "code": "INVALID_CURRENT_PASSWORD",
                "errors": {
                    "current_password": ["invalid"]
                }
            })

        if current_pw == new_pw:
            raise serializers.ValidationError({
                "code": "PASSWORD_SAME_AS_OLD",
                "errors": {
                    "new_password": ["must_be_different"]
                }
            })

        return attrs


class ProfileUpdateSerializer(serializers.Serializer):
    first_name = serializers.CharField(max_length=256, required=False, allow_blank=True)
    last_name = serializers.CharField(max_length=256, required=False, allow_blank=True)
    mobile = serializers.CharField(max_length=20, required=False, allow_blank=True)

    def validate(self, attrs):
        if not attrs:
            raise serializers.ValidationError({"code": "PROFILE_NO_DATA"})
        return attrs
