"""Role enum + PERMISSIONS matrix."""

from __future__ import annotations

from enum import Enum


class Role(str, Enum):
    ADMIN = "admin"
    USER = "user"
    VIEWER = "viewer"


ALL_ROLES = {Role.ADMIN, Role.USER, Role.VIEWER}
WRITE_ROLES = {Role.ADMIN, Role.USER}
ADMIN_ONLY = {Role.ADMIN}


# (method, path-prefix) → allowed roles.
# Endpoints not in this matrix default to DENY (fail-closed).
PERMISSIONS: dict[tuple[str, str], set[Role]] = {
    # Public paths.
    ("GET", "/api/health"): set(),
    ("POST", "/api/auth/login"): set(),

    # Auth surface.
    ("POST", "/api/auth/logout"): ALL_ROLES,
    ("GET", "/api/auth/me"): ALL_ROLES,

    # Admin-only user management.
    ("GET", "/api/admin/users"): ADMIN_ONLY,
    ("POST", "/api/admin/users"): ADMIN_ONLY,
    ("PATCH", "/api/admin/users"): ADMIN_ONLY,
    ("DELETE", "/api/admin/users"): ADMIN_ONLY,

    # Read endpoints (all authenticated roles).
    ("GET", "/api/claims"): ALL_ROLES,
    ("GET", "/api/remittances"): ALL_ROLES,
    ("GET", "/api/providers"): ALL_ROLES,
    ("GET", "/api/batches"): ALL_ROLES,
    ("GET", "/api/dashboard/summary"): ALL_ROLES,
    ("GET", "/api/activity"): ALL_ROLES,
    ("GET", "/api/inbox/lanes"): ALL_ROLES,
    ("GET", "/api/inbox/export.csv"): ALL_ROLES,
    ("GET", "/api/reconcile"): ALL_ROLES,
    ("GET", "/api/reconciliation"): ALL_ROLES,
    ("GET", "/api/acks"): ALL_ROLES,
    ("GET", "/api/ta1-acks"): ALL_ROLES,
    ("GET", "/api/277ca-acks"): ALL_ROLES,
    ("GET", "/api/batch-diff"): ALL_ROLES,
    ("GET", "/api/config"): ALL_ROLES,
    ("GET", "/api/payers"): ALL_ROLES,
    ("GET", "/api/audit-log"): ADMIN_ONLY,

    # Clearhouse (SFTP creds + dzinesco identity) — admin only.
    ("GET", "/api/clearhouse"): ADMIN_ONLY,
    ("PATCH", "/api/clearhouse"): ADMIN_ONLY,
    ("POST", "/api/clearhouse/submit"): ADMIN_ONLY,

    # Admin ops (audit log, backup, scheduler, db rotate, reload-config).
    ("GET", "/api/admin/audit-log"): ADMIN_ONLY,
    ("GET", "/api/admin/audit-log/verify"): ADMIN_ONLY,
    ("GET", "/api/admin/backup"): ADMIN_ONLY,
    ("POST", "/api/admin/backup"): ADMIN_ONLY,
    ("GET", "/api/admin/backup/scheduler"): ADMIN_ONLY,
    ("POST", "/api/admin/backup/scheduler"): ADMIN_ONLY,
    ("GET", "/api/admin/scheduler"): ADMIN_ONLY,
    ("POST", "/api/admin/scheduler"): ADMIN_ONLY,
    ("POST", "/api/admin/db/rotate-key"): ADMIN_ONLY,
    ("POST", "/api/admin/reload-config"): ADMIN_ONLY,
    ("GET", "/api/admin/validate-provider"): ADMIN_ONLY,

    # Write endpoints (admin + user, no viewer).
    ("POST", "/api/parse-837"): WRITE_ROLES,
    ("POST", "/api/parse-835"): WRITE_ROLES,
    ("POST", "/api/parse-999"): WRITE_ROLES,
    ("POST", "/api/parse-ta1"): WRITE_ROLES,
    ("POST", "/api/parse-277ca"): WRITE_ROLES,
    ("POST", "/api/inbox"): WRITE_ROLES,
    ("POST", "/api/inbox/candidates"): WRITE_ROLES,
    ("POST", "/api/inbox/rejected"): WRITE_ROLES,
    ("POST", "/api/inbox/payer-rejected"): WRITE_ROLES,
    ("POST", "/api/reconcile"): WRITE_ROLES,
    ("POST", "/api/reconciliation"): WRITE_ROLES,
    ("POST", "/api/resubmit"): WRITE_ROLES,
    ("POST", "/api/acks"): WRITE_ROLES,
    ("POST", "/api/batches"): WRITE_ROLES,  # /export-837 regenerates X12 from DB rows
    ("POST", "/api/eligibility"): WRITE_ROLES,

    # CSV export — read-only.
    ("GET", "/api/export.csv"): ALL_ROLES,
}


def allowed_roles(method: str, path: str) -> set[Role] | None:
    """Return the set of roles allowed to call (method, path), or None if denied.

    Uses longest-prefix match on path; falls back to DENY (None) if no entry matches.
    """
    candidates = [
        (len(prefix), roles)
        for (m, prefix), roles in PERMISSIONS.items()
        if m == method and (path == prefix or path.startswith(prefix.rstrip("/") + "/"))
    ]
    if not candidates:
        return None
    candidates.sort(key=lambda x: -x[0])
    return candidates[0][1]