"""Admin permission catalogue, decorators and audit logging."""
from datetime import datetime
from flask import abort, flash, jsonify, redirect, request, session, url_for
from functools import wraps

from nexora.config import ADMIN_USERNAME
from nexora.core import app
from nexora.database.connection import execute, query


def admin_required(view):
    @wraps(view)
    def wrapped(*args, **kwargs):
        if not session.get("admin"):
            if request.is_json or request.path.endswith("/verify") or request.path.endswith("/decision") or request.path.endswith("/confirm-payment"):
                return jsonify({"ok": False, "status": "unauthorized", "message": "Admin login required."}), 401
            flash("Admin login required.", "warning")
            return redirect(url_for("admin_login"))
        # Verify session has not been revoked â€” check user still exists and is active
        username = session.get("admin_username", "")
        if username != ADMIN_USERNAME:
            staff = query("SELECT active FROM admin_users WHERE username = ?", (username,), one=True)
            if not staff or not staff["active"]:
                session.clear()
                flash("Your account has been deactivated.", "danger")
                return redirect(url_for("admin_login"))
        return view(*args, **kwargs)

    return wrapped


PERMISSIONS = [
    ("view_dashboard", "View dashboard"),
    ("games_view", "Games: view"),
    ("games_create", "Games: create"),
    ("games_update", "Games: edit/update"),
    ("games_delete", "Games: delete"),
    ("media_view", "Media: view"),
    ("media_create", "Media: create/upload"),
    ("media_update", "Media: edit/update"),
    ("media_delete", "Media: delete"),
    ("leadership_view", "Leadership: view"),
    ("leadership_create", "Leadership: create"),
    ("leadership_update", "Leadership: edit/update"),
    ("leadership_delete", "Leadership: delete"),
    ("sponsors_view", "Sponsors: view"),
    ("sponsors_create", "Sponsors: create"),
    ("sponsors_update", "Sponsors: edit/update"),
    ("sponsors_delete", "Sponsors: delete"),
    ("prize_pool_view", "Prize Pool: view"),
    ("prize_pool_update", "Prize Pool: update settings/banner"),
    ("prize_items_create", "Prize Items: create"),
    ("prize_items_update", "Prize Items: edit/update"),
    ("prize_items_delete", "Prize Items: delete"),
    ("team_view", "Our Team: view"),
    ("team_create", "Our Team: create"),
    ("team_update", "Our Team: edit/update/reorder"),
    ("team_delete", "Our Team: delete"),
    ("contacts_view", "Messages: view"),
    ("contacts_delete", "Messages: delete"),
    ("settings_view", "Settings: view"),
    ("settings_update", "Settings: update"),
    ("users_view", "Staff Users: view"),
    ("users_create", "Staff Users: create"),
    ("users_update", "Staff Users: edit/update/reset passwords"),
    ("users_delete", "Staff Users: delete"),
    ("roles_view", "Roles: view"),
    ("roles_create", "Roles: create"),
    ("roles_update", "Roles: edit/update permissions"),
    ("roles_delete", "Roles: delete"),
    ("registrations_delete", "Registrations: delete"),
    ("manage_games", "Manage game cards (add, edit, delete)"),
    ("manage_media", "Manage covers and gallery"),
    ("manage_leadership", "Manage leadership quotes"),
    ("manage_sponsors", "Manage sponsors"),
    ("manage_prize_pool", "Manage prize pool and rewards"),
    ("manage_team", "Manage Our Team sections and members"),
    ("manage_contacts", "View and manage messages"),
    ("manage_settings", "Manage website and payment settings"),
    ("view_registrations", "View registrations"),
    ("edit_registrations", "Edit registrations"),
    ("view_payment_details", "View payment details"),
    ("confirm_payments", "Confirm payments"),
    ("process_refunds", "Process refunds"),
    ("download_pdf_tickets", "Download PDF tickets"),
    ("export_excel_reports", "Export Excel reports"),
    ("scan_qr_codes", "Scan QR codes"),
    ("manually_verify_tickets", "Manually verify tickets"),
    ("view_scanned_record", "View scanned ticket record details"),
    ("approve_entry", "Approve entry"),
    ("reject_entry", "Reject entry"),
    ("view_checkin_history", "View check-in history"),
    ("override_duplicate_entry", "Override duplicate entry"),
    ("manage_users", "Manage users"),
    ("manage_roles_permissions", "Manage roles and permissions"),
    ("view_audit_logs", "View audit logs"),
]


PERMISSION_KEYS = {key for key, _label in PERMISSIONS}


PERMISSION_LABELS = dict(PERMISSIONS)


PERMISSION_ALIASES = {
    "manage_games": {"games_view", "games_create", "games_update", "games_delete"},
    "manage_media": {"media_view", "media_create", "media_update", "media_delete"},
    "manage_leadership": {"leadership_view", "leadership_create", "leadership_update", "leadership_delete"},
    "manage_sponsors": {"sponsors_view", "sponsors_create", "sponsors_update", "sponsors_delete"},
    "manage_prize_pool": {"prize_pool_view", "prize_pool_update", "prize_items_create", "prize_items_update", "prize_items_delete"},
    "manage_team": {"team_view", "team_create", "team_update", "team_delete"},
    "manage_contacts": {"contacts_view", "contacts_delete"},
    "manage_settings": {"settings_view", "settings_update"},
    "manage_users": {"users_view", "users_create", "users_update", "users_delete"},
    "manage_roles_permissions": {"roles_view", "roles_create", "roles_update", "roles_delete"},
    "edit_registrations": {"registrations_delete"},
}


PERMISSION_SECTIONS = [
    ("Dashboard", ["view_dashboard"]),
    ("Game Cards", ["games_view", "games_create", "games_update", "games_delete", "manage_games"]),
    ("Covers & Gallery", ["media_view", "media_create", "media_update", "media_delete", "manage_media"]),
    ("Leadership", ["leadership_view", "leadership_create", "leadership_update", "leadership_delete", "manage_leadership"]),
    ("Sponsors", ["sponsors_view", "sponsors_create", "sponsors_update", "sponsors_delete", "manage_sponsors"]),
    ("Prize Pool", ["prize_pool_view", "prize_pool_update", "prize_items_create", "prize_items_update", "prize_items_delete", "manage_prize_pool"]),
    ("Our Team", ["team_view", "team_create", "team_update", "team_delete", "manage_team"]),
    ("Messages & Settings", ["contacts_view", "contacts_delete", "settings_view", "settings_update", "manage_contacts", "manage_settings"]),
    ("Registrations & Payments", ["view_registrations", "edit_registrations", "registrations_delete", "view_payment_details", "confirm_payments", "process_refunds", "download_pdf_tickets", "export_excel_reports"]),
    ("QR Check-In", ["scan_qr_codes", "manually_verify_tickets", "view_scanned_record", "approve_entry", "reject_entry", "view_checkin_history", "override_duplicate_entry"]),
    ("Staff Users", ["users_view", "users_create", "users_update", "users_delete", "manage_users"]),
    ("Roles & Audit", ["roles_view", "roles_create", "roles_update", "roles_delete", "manage_roles_permissions", "view_audit_logs"]),
]


def current_permissions():
    """The configured root admin always retains full access."""
    if session.get("admin_username") == ADMIN_USERNAME:
        return PERMISSION_KEYS
    perms = set()
    role_id = session.get("role_id")
    if role_id:
        perms = {row["permission_key"] for row in query("SELECT permission_key FROM role_permissions WHERE role_id = ?", (role_id,))}
    user_id = session.get("admin_user_id")
    if user_id:
        user_perms = {row["permission_key"] for row in query("SELECT permission_key FROM user_permissions WHERE user_id = ?", (user_id,))}
        perms |= user_perms
    expanded = set(perms)
    for key in tuple(perms):
        expanded |= PERMISSION_ALIASES.get(key, set())
    return expanded


def has_permission(permission):
    return permission in current_permissions()


def forbidden_response():
    if request.is_json or request.path.endswith("/verify") or request.path.endswith("/decision"):
        return jsonify({"ok": False, "status": "forbidden", "message": "403 Forbidden: you do not have permission for this action."}), 403
    abort(403)


def permission_required(*permissions, any_of=False):
    def decorator(view):
        @wraps(view)
        def wrapped(*args, **kwargs):
            if not session.get("admin"):
                return admin_required(view)(*args, **kwargs)
            granted = current_permissions()
            allowed = bool(set(permissions) & granted) if any_of else set(permissions).issubset(granted)
            if not allowed:
                return forbidden_response()
            return view(*args, **kwargs)
        return wrapped
    return decorator


@app.context_processor
def inject_permissions():
    try:
        granted = current_permissions() if session.get("admin") else set()
    except RuntimeError:
        granted = set()
    return {
        "can": lambda key: key in granted,
        "can_any": lambda *keys: bool(set(keys) & granted),
        "admin_permissions": granted,
    }


def log_role_audit(action, target_username="", details=""):
    execute(
        "INSERT INTO role_audit_log (actor_username, action, target_username, details, created_at) VALUES (?, ?, ?, ?, ?)",
        (session.get("admin_username", "system"), action, target_username, details, datetime.now().isoformat(timespec="seconds")),
    )
