"""
Permission service for role-based and per-user access control.
"""
from typing import Dict, List, Optional
from sqlalchemy.orm import Session

from app.models.permission import (
    RolePermission, UserPermissionOverride,
    PermissionResource, PermissionAction
)
from app.models.user import UserRole


# Default permission matrix per role
DEFAULT_PERMISSIONS: Dict[str, Dict[str, List[str]]] = {
    UserRole.ADMIN: {
        # Admin has MANAGE (full control) on every resource
        r.value: [a.value for a in PermissionAction]
        for r in PermissionResource
    },
    UserRole.MANAGER: {
        PermissionResource.USERS.value:         [PermissionAction.READ.value],
        PermissionResource.ESTABLISHMENTS.value:[PermissionAction.READ.value, PermissionAction.UPDATE.value],
        PermissionResource.ROOMS.value:         [PermissionAction.READ.value, PermissionAction.UPDATE.value],
        PermissionResource.ROOM_TYPES.value:    [PermissionAction.READ.value],
        PermissionResource.CLIENTS.value:       [PermissionAction.READ.value],
        PermissionResource.DOCUMENTS.value:     [PermissionAction.READ.value],
        PermissionResource.RESERVATIONS.value:  [PermissionAction.READ.value],
        PermissionResource.CHECKIN.value:       [PermissionAction.READ.value],
        PermissionResource.FOLIOS.value:        [PermissionAction.READ.value],
        PermissionResource.PAYMENTS.value:      [PermissionAction.READ.value],
        PermissionResource.INVOICES.value:      [PermissionAction.READ.value, PermissionAction.EXPORT.value],
        PermissionResource.DEPARTMENTS.value:   [PermissionAction.READ.value, PermissionAction.UPDATE.value],
        PermissionResource.REPORTS.value:       [PermissionAction.READ.value, PermissionAction.EXPORT.value],
        PermissionResource.BUDGETS.value:       [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.UPDATE.value, PermissionAction.APPROVE.value,
            PermissionAction.EXPORT.value
        ],
        PermissionResource.LOYALTY.value:       [PermissionAction.READ.value],
        PermissionResource.WAITLIST.value:      [PermissionAction.READ.value],
        PermissionResource.NOTIFICATIONS.value: [PermissionAction.READ.value],
    },
    UserRole.RECEPTION: {
        PermissionResource.USERS.value:         [],
        PermissionResource.ESTABLISHMENTS.value:[PermissionAction.READ.value],
        PermissionResource.ROOMS.value:         [PermissionAction.READ.value, PermissionAction.UPDATE.value],
        PermissionResource.ROOM_TYPES.value:    [PermissionAction.READ.value],
        PermissionResource.CLIENTS.value:       [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.UPDATE.value
        ],
        PermissionResource.DOCUMENTS.value:     [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.UPDATE.value
        ],
        PermissionResource.RESERVATIONS.value:  [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.UPDATE.value
        ],
        PermissionResource.CHECKIN.value:       [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.UPDATE.value
        ],
        PermissionResource.FOLIOS.value:        [PermissionAction.READ.value, PermissionAction.CREATE.value],
        PermissionResource.PAYMENTS.value:      [PermissionAction.READ.value, PermissionAction.CREATE.value],
        PermissionResource.INVOICES.value:      [PermissionAction.READ.value, PermissionAction.EXPORT.value],
        PermissionResource.DEPARTMENTS.value:   [PermissionAction.READ.value],
        PermissionResource.REPORTS.value:       [PermissionAction.READ.value],
        PermissionResource.BUDGETS.value:       [],
        PermissionResource.LOYALTY.value:       [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.UPDATE.value
        ],
        PermissionResource.WAITLIST.value:      [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.UPDATE.value
        ],
        PermissionResource.NOTIFICATIONS.value: [PermissionAction.READ.value],
    },
    UserRole.ACCOUNTING: {
        PermissionResource.USERS.value:         [],
        PermissionResource.ESTABLISHMENTS.value:[PermissionAction.READ.value],
        PermissionResource.ROOMS.value:         [PermissionAction.READ.value],
        PermissionResource.ROOM_TYPES.value:    [PermissionAction.READ.value],
        PermissionResource.CLIENTS.value:       [PermissionAction.READ.value, PermissionAction.UPDATE.value],
        PermissionResource.DOCUMENTS.value:     [PermissionAction.READ.value],
        PermissionResource.RESERVATIONS.value:  [PermissionAction.READ.value],
        PermissionResource.CHECKIN.value:       [PermissionAction.READ.value],
        PermissionResource.FOLIOS.value:        [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.UPDATE.value, PermissionAction.DELETE.value
        ],
        PermissionResource.PAYMENTS.value:      [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.UPDATE.value
        ],
        PermissionResource.INVOICES.value:      [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.EXPORT.value
        ],
        PermissionResource.DEPARTMENTS.value:   [PermissionAction.READ.value],
        PermissionResource.REPORTS.value:       [
            PermissionAction.READ.value, PermissionAction.EXPORT.value
        ],
        PermissionResource.BUDGETS.value:       [
            PermissionAction.READ.value, PermissionAction.CREATE.value,
            PermissionAction.UPDATE.value
        ],
        PermissionResource.LOYALTY.value:       [PermissionAction.READ.value],
        PermissionResource.WAITLIST.value:      [PermissionAction.READ.value],
        PermissionResource.NOTIFICATIONS.value: [PermissionAction.READ.value],
    },
}


class PermissionService:
    """Service for checking and managing permissions."""

    def __init__(self, db: Session):
        self.db = db

    def has_permission(
        self,
        user_id: int,
        role: str,
        resource: PermissionResource,
        action: PermissionAction
    ) -> bool:
        """
        Check if a user has permission to perform an action on a resource.

        Priority order:
        1. User-level override (most specific, overrides role)
        2. Role-level permission in DB
        3. Default permission matrix (fallback)
        """
        # 1. Check user-level override first
        override = self.db.query(UserPermissionOverride).filter(
            UserPermissionOverride.user_id == user_id,
            UserPermissionOverride.resource == resource,
            UserPermissionOverride.action == action
        ).first()

        if override is not None:
            return override.is_allowed

        # 2. Check DB role permission
        role_perm = self.db.query(RolePermission).filter(
            RolePermission.role == role,
            RolePermission.resource == resource,
            RolePermission.action == action
        ).first()

        if role_perm is not None:
            return role_perm.is_allowed

        # 3. Fallback to default matrix
        role_defaults = DEFAULT_PERMISSIONS.get(role, {})
        allowed_actions = role_defaults.get(resource.value, [])
        return action.value in allowed_actions

    def get_user_permissions(self, user_id: int, role: str) -> Dict[str, List[str]]:
        """Get all effective permissions for a user (merged role + overrides)."""
        # Start from role defaults
        permissions = {}
        role_defaults = DEFAULT_PERMISSIONS.get(role, {})

        for resource in PermissionResource:
            allowed = list(role_defaults.get(resource.value, []))
            permissions[resource.value] = allowed

        # Apply DB role permissions (override defaults)
        db_role_perms = self.db.query(RolePermission).filter(
            RolePermission.role == role
        ).all()

        for rp in db_role_perms:
            res = rp.resource.value
            act = rp.action.value
            if rp.is_allowed and act not in permissions.get(res, []):
                permissions.setdefault(res, []).append(act)
            elif not rp.is_allowed and act in permissions.get(res, []):
                permissions[res].remove(act)

        # Apply user-level overrides
        user_overrides = self.db.query(UserPermissionOverride).filter(
            UserPermissionOverride.user_id == user_id
        ).all()

        for uo in user_overrides:
            res = uo.resource.value
            act = uo.action.value
            if uo.is_allowed and act not in permissions.get(res, []):
                permissions.setdefault(res, []).append(act)
            elif not uo.is_allowed and act in permissions.get(res, []):
                permissions[res].remove(act)

        return permissions

    def initialize_default_permissions(self) -> int:
        """
        Seed the database with the default role permission matrix.
        Skips existing records.
        Returns number of permissions created.
        """
        created = 0
        for role, resource_map in DEFAULT_PERMISSIONS.items():
            for resource_str, actions in resource_map.items():
                try:
                    resource = PermissionResource(resource_str)
                except ValueError:
                    continue

                for action_str in actions:
                    try:
                        action = PermissionAction(action_str)
                    except ValueError:
                        continue

                    existing = self.db.query(RolePermission).filter(
                        RolePermission.role == role,
                        RolePermission.resource == resource,
                        RolePermission.action == action
                    ).first()

                    if not existing:
                        perm = RolePermission(
                            role=role,
                            resource=resource,
                            action=action,
                            is_allowed=True,
                            description=f"Default permission: {role} can {action_str} {resource_str}"
                        )
                        self.db.add(perm)
                        created += 1

        self.db.commit()
        return created
