from __future__ import annotations

from rest_framework import serializers

from apps.access.models import Permission, Role, UserPermissionOverride
from apps.audit.models import AuditLog
from apps.organizations.models import Organization, OrganizationMembership

SCOPES = ["self", "team", "unit", "organization", "assigned_organizations", "all"]


class LoginSerializer(serializers.Serializer):
    identifier = serializers.CharField()
    password = serializers.CharField()


class UserBriefSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    username = serializers.CharField(allow_null=True)
    name = serializers.CharField(allow_null=True)
    mobile = serializers.CharField(allow_null=True)
    mobile_verified = serializers.SerializerMethodField()
    personnel_code = serializers.CharField()
    has_name = serializers.SerializerMethodField()

    def get_mobile_verified(self, obj) -> bool:
        return obj.mobile_verified_at is not None

    def get_has_name(self, obj) -> bool:
        return bool(obj.name)


class OrganizationSerializer(serializers.ModelSerializer):
    logo_url = serializers.SerializerMethodField()

    class Meta:
        model = Organization
        fields = ["id", "name", "slug", "kind", "is_active", "accent_color", "logo_url", "created_at"]

    def get_logo_url(self, obj) -> str | None:
        # path only (e.g. /media/org-logos/1-2026.png); the SPA prefixes the API host
        return obj.logo.url if obj.logo else None


class OrganizationManagerSerializer(serializers.Serializer):
    username = serializers.CharField(max_length=50)
    password = serializers.CharField(write_only=True)
    name = serializers.CharField(max_length=255, required=False, allow_blank=True, default="")


class OrganizationCreateSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=255)
    slug = serializers.SlugField(max_length=64)
    # optional first manager of the new organization (created together with it)
    manager = OrganizationManagerSerializer(required=False)


class OrganizationUpdateSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=255, required=False)
    is_active = serializers.BooleanField(required=False)


class PermissionSerializer(serializers.ModelSerializer):
    module = serializers.CharField(source="module_id")

    class Meta:
        model = Permission
        fields = ["code", "module", "action", "name_fa", "is_platform_only"]


class RoleSerializer(serializers.ModelSerializer):
    grants = serializers.SerializerMethodField()

    class Meta:
        model = Role
        fields = ["id", "code", "name", "is_system", "is_active", "grants"]

    def get_grants(self, role):
        return [
            {"code": g.permission.code, "scope": g.scope, "can_delegate": g.can_delegate}
            for g in role.grants.all()
        ]


class RoleCreateSerializer(serializers.Serializer):
    code = serializers.SlugField(max_length=50)
    name = serializers.CharField(max_length=120)


class RoleUpdateSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=120, required=False)
    is_active = serializers.BooleanField(required=False)


class GrantItemSerializer(serializers.Serializer):
    code = serializers.CharField(max_length=100)
    scope = serializers.ChoiceField(choices=SCOPES, default="self")
    can_delegate = serializers.BooleanField(default=False)


class RoleGrantsSerializer(serializers.Serializer):
    grants = GrantItemSerializer(many=True)


class MemberSerializer(serializers.ModelSerializer):
    user = UserBriefSerializer(read_only=True)
    roles = serializers.SerializerMethodField()

    class Meta:
        model = OrganizationMembership
        fields = ["id", "user", "personnel_code", "status", "joined_at", "roles"]

    def get_roles(self, membership):
        return [
            {"id": mr.role_id, "code": mr.role.code, "name": mr.role.name}
            for mr in membership.membership_roles.all()
        ]


class MemberCreateSerializer(serializers.Serializer):
    username = serializers.CharField(max_length=50)
    password = serializers.CharField(write_only=True)
    name = serializers.CharField(max_length=255, required=False, allow_blank=True, default="")
    mobile = serializers.CharField(max_length=20, required=False, allow_blank=True, allow_null=True)
    personnel_code = serializers.CharField(max_length=50, required=False, allow_blank=True, allow_null=True)
    role_ids = serializers.ListField(child=serializers.IntegerField(), required=False, default=list)


class MemberLinkSerializer(serializers.Serializer):
    username = serializers.CharField(max_length=50)
    personnel_code = serializers.CharField(max_length=50, required=False, allow_blank=True, allow_null=True)


class MemberUpdateSerializer(serializers.Serializer):
    status = serializers.ChoiceField(choices=OrganizationMembership.Status.values, required=False)
    personnel_code = serializers.CharField(max_length=50, required=False, allow_blank=True, allow_null=True)
    name = serializers.CharField(max_length=255, required=False, allow_blank=True)
    username = serializers.CharField(max_length=50, required=False, allow_blank=True)
    mobile = serializers.CharField(max_length=20, required=False, allow_blank=True, allow_null=True)
    password = serializers.CharField(write_only=True, required=False, allow_blank=True)
    mobile_verified = serializers.BooleanField(required=False)


class MemberRolesSerializer(serializers.Serializer):
    role_ids = serializers.ListField(child=serializers.IntegerField())


class OverrideInputSerializer(serializers.Serializer):
    permission = serializers.CharField(max_length=100)
    effect = serializers.ChoiceField(choices=["allow", "deny"])
    scope = serializers.ChoiceField(choices=SCOPES, default="self")
    can_delegate = serializers.BooleanField(default=False)
    reason = serializers.CharField(max_length=255, required=False, allow_blank=True, default="")
    expires_at = serializers.DateTimeField(required=False, allow_null=True, default=None)


class OverrideSerializer(serializers.ModelSerializer):
    permission = serializers.CharField(source="permission.code")

    class Meta:
        model = UserPermissionOverride
        fields = ["id", "permission", "effect", "scope", "can_delegate", "reason", "expires_at", "created_at"]


class StaffAssignmentsSerializer(serializers.Serializer):
    organization_ids = serializers.ListField(child=serializers.IntegerField())


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

    class Meta:
        model = AuditLog
        fields = ["id", "created_at", "actor", "action", "entity_type", "entity_id", "before", "after", "ip_address"]

    def get_actor(self, log):
        if log.actor_id is None:
            return None
        return {"id": log.actor_id, "username": log.actor.username, "name": log.actor.name}
