"""Code-side registry: the single source of truth for modules, their permissions,
dependencies and menu metadata.

Adding a module = adding a ModuleSpec here (plus its own Django app). Nothing in the
core needs rewriting. `python manage.py sync_registry` mirrors this into the database.
"""
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Optional


@dataclass(frozen=True)
class PermissionSpec:
    code: str
    action: str
    name_fa: str
    platform_only: bool = False  # can only ever be held by NoTeam staff, never inside a customer org


@dataclass(frozen=True)
class NavSpec:
    key: str
    label_fa: str
    path: str
    group: str = ""
    permission: Optional[str] = None  # None => visible to every active member
    min_scope: Optional[str] = None
    sort_order: int = 0
    platform_only: bool = False  # shown only while the NoTeam platform organization is selected


@dataclass(frozen=True)
class ModuleSpec:
    code: str
    title_fa: str
    description_fa: str = ""
    status: str = "available"  # available | planned
    is_core: bool = False
    depends_on: tuple[str, ...] = ()
    permissions: tuple[PermissionSpec, ...] = ()
    nav: tuple[NavSpec, ...] = ()
    sort_order: int = 0
    # Given to the "employee" role of an organization the first time the module is enabled for it
    # (the organization manager role always gets every permission of the module).
    employee_grants: tuple[tuple[str, str], ...] = ()


def _p(code: str, name_fa: str, platform_only: bool = False) -> PermissionSpec:
    return PermissionSpec(code=code, action=code.split(".", 1)[1], name_fa=name_fa, platform_only=platform_only)


CORE = ModuleSpec(
    code="core",
    title_fa="هسته سامانه",
    description_fa="مدیریت مجموعه‌ها، کاربران، نقش‌ها، ماژول‌ها و گزارش فعالیت‌ها",
    is_core=True,
    sort_order=0,
    permissions=(
        _p("organizations.view", "مشاهده مجموعه‌ها", platform_only=True),
        _p("organizations.create", "ایجاد مجموعه", platform_only=True),
        _p("organizations.update", "ویرایش و غیرفعال‌سازی مجموعه", platform_only=True),
        _p("members.view", "مشاهده اعضا"),
        _p("members.create", "افزودن عضو"),
        _p("members.update", "ویرایش عضو"),
        _p("members.delete", "غیرفعال‌سازی عضو"),
        _p("members.link", "اتصال حساب موجود به مجموعه", platform_only=True),
        _p("roles.view", "مشاهده نقش‌ها"),
        _p("roles.manage", "مدیریت نقش‌ها"),
        _p("access.manage", "مدیریت دسترسی اختصاصی اعضا"),
        _p("modules.view", "مشاهده ماژول‌ها"),
        _p("modules.manage", "فعال و غیرفعال‌سازی ماژول", platform_only=True),
        _p("audit.view", "مشاهده گزارش فعالیت‌ها"),
        _p("settings.view", "مشاهده تنظیمات"),
        _p("settings.manage", "مدیریت تنظیمات"),
    ),
    nav=(
        NavSpec("dashboard", "داشبورد", "/dashboard", group="", sort_order=0),
        # every member; its own last group so it sits at the bottom of the menu
        NavSpec("settings", "تنظیمات", "/settings", group="حساب کاربری", sort_order=999),
        NavSpec("members", "کاربران", "/admin/members", "مدیریت", "members.view", sort_order=10),
        NavSpec("roles", "نقش‌ها و دسترسی‌ها", "/admin/roles", "مدیریت", "roles.view", sort_order=11),
        NavSpec("organizations", "مجموعه‌ها", "/admin/organizations", "مدیریت", "organizations.view", sort_order=12, platform_only=True),
        NavSpec("modules", "ماژول‌ها", "/admin/modules", "مدیریت", "modules.view", sort_order=13),
        NavSpec("audit", "گزارش فعالیت‌ها", "/admin/audit", "مدیریت", "audit.view", sort_order=14),
        NavSpec("module_requests", "درخواست ماژول‌ها", "/admin/module-requests", "مدیریت", "modules.manage", sort_order=15, platform_only=True),
    ),
)

ATTENDANCE = ModuleSpec(
    code="attendance",
    title_fa="حضور و غیاب",
    description_fa="ثبت رفت‌وآمد، مرخصی، تعطیلات، تاخیر و اضافه‌کار و گزارش‌های کارکرد",
    sort_order=10,
    permissions=(
        _p("attendance.view", "مشاهده حضور و غیاب"),
        _p("attendance.create", "ثبت حضور و درخواست مرخصی"),
        _p("attendance.update", "ویرایش رکورد حضور"),
        _p("attendance.delete", "حذف رکورد حضور"),
        _p("attendance.approve", "تأیید یا رد مرخصی"),
        _p("attendance.report", "دریافت گزارش حضور"),
        _p("attendance.export", "خروجی گرفتن از گزارش‌ها"),
        _p("attendance.manage_settings", "مدیریت تنظیمات حضور و تعطیلات"),
    ),
    nav=(
        NavSpec("attendance_leave", "مرخصی", "/leave-requests", "", "attendance.create", sort_order=2),
        NavSpec("attendance_report", "گزارش‌های حضور", "/admin/report", "منابع انسانی", "attendance.report", sort_order=22),
        NavSpec("attendance_review", "بررسی مرخصی‌ها", "/admin/leave-requests", "منابع انسانی", "attendance.approve", sort_order=23),
        NavSpec("attendance_punches", "تأیید مکان ثبت", "/admin/punches", "منابع انسانی", "attendance.approve", sort_order=24),
        NavSpec("attendance_settings", "تعطیلات و ساعت کاری", "/admin/holidays", "منابع انسانی", "attendance.manage_settings", sort_order=25),
        NavSpec("attendance_location", "محل ثبت ورود و خروج", "/admin/work-location", "منابع انسانی", "attendance.manage_settings", sort_order=26),
    ),
)


TASKS = ModuleSpec(
    code="tasks",
    title_fa="مدیریت وظایف",
    description_fa="تعریف وظیفه، واگذاری به همکاران، پیگیری وضعیت و موعد",
    sort_order=20,
    permissions=(
        _p("tasks.view", "مشاهده وظایف"),
        _p("tasks.create", "ایجاد وظیفه"),
        _p("tasks.update", "ویرایش وظیفه"),
        _p("tasks.delete", "حذف وظیفه"),
        _p("tasks.assign", "واگذاری وظیفه به دیگران"),
        _p("tasks.approve", "تأیید یا رد انجام وظیفه"),
    ),
    employee_grants=(("tasks.view", "self"), ("tasks.create", "self"), ("tasks.update", "self")),
    nav=(NavSpec("tasks", "وظایف", "/tasks", "", "tasks.view", sort_order=1),),
)


PERSONNEL = ModuleSpec(
    code="personnel",
    title_fa="مدیریت پرسنل و قراردادها",
    description_fa="پرونده‌ی پرسنلی، سمت و واحد، تاریخ استخدام و قراردادها",
    sort_order=30,
    permissions=(
        _p("personnel.view", "مشاهده پرونده‌ی پرسنلی"),
        _p("personnel.update", "ویرایش پرونده‌ی پرسنلی"),
        _p("personnel.contracts_view", "مشاهده قراردادها و حقوق"),
        _p("personnel.contracts_manage", "مدیریت قراردادها"),
    ),
    employee_grants=(("personnel.view", "self"),),
    nav=(NavSpec("personnel", "پرسنل", "/personnel", "منابع انسانی", "personnel.view", sort_order=27),),
)


PAYROLL = ModuleSpec(
    code="payroll",
    title_fa="حقوق و دستمزد",
    description_fa="محاسبه‌ی ماهانه‌ی حقوق از قرارداد و گزارش حضور، اضافه‌کار، کسورات و فیش حقوقی",
    depends_on=("attendance", "personnel"),
    sort_order=40,
    permissions=(
        _p("payroll.view", "مشاهده حقوق و فیش"),
        _p("payroll.manage", "ایجاد و محاسبه‌ی حقوق"),
        _p("payroll.approve", "تأیید نهایی حقوق"),
        _p("payroll.settings", "تنظیمات حقوق و اضافه‌کار"),
    ),
    employee_grants=(("payroll.view", "self"),),
    nav=(NavSpec("payroll", "حقوق و دستمزد", "/payroll", "منابع انسانی", "payroll.view", sort_order=28),),
)


CRM = ModuleSpec(
    code="crm",
    title_fa="مدیریت ارتباط با مشتری",
    description_fa="مشتریان و سرنخ‌ها، مسئول پیگیری، سابقه‌ی تماس و جلسه و یادآوری پیگیری",
    sort_order=50,
    permissions=(
        _p("crm.view", "مشاهده مشتریان"),
        _p("crm.create", "ثبت مشتری"),
        _p("crm.update", "ویرایش مشتری و ثبت پیگیری"),
        _p("crm.delete", "حذف مشتری"),
        _p("crm.assign", "تعیین مسئول مشتری"),
    ),
    employee_grants=(("crm.view", "self"), ("crm.create", "self"), ("crm.update", "self")),
    nav=(NavSpec("crm", "مشتریان", "/crm", "فروش", "crm.view", sort_order=30),),
)


INVOICING = ModuleSpec(
    code="invoicing",
    title_fa="فاکتورساز",
    description_fa="صدور فاکتور برای مشتریان، مالیات و تخفیف، شماره‌ی ترتیبی، ثبت پرداخت و چاپ",
    depends_on=("crm",),
    sort_order=80,
    permissions=(
        _p("invoicing.view", "مشاهده فاکتورها"),
        _p("invoicing.create", "ایجاد فاکتور"),
        _p("invoicing.update", "ویرایش پیش‌نویس فاکتور"),
        _p("invoicing.delete", "حذف پیش‌نویس فاکتور"),
        _p("invoicing.issue", "صدور فاکتور"),
        _p("invoicing.settle", "ثبت پرداخت فاکتور"),
        _p("invoicing.cancel", "ابطال فاکتور"),
    ),
    nav=(NavSpec("invoicing", "فاکتورها", "/invoicing", "فروش", "invoicing.view", sort_order=31),),
)


FINANCE = ModuleSpec(
    code="finance",
    title_fa="امور مالی",
    description_fa="حساب‌های بانکی و صندوق، ثبت درآمد و هزینه، دسته‌بندی و گزارش ماهانه",
    sort_order=70,
    permissions=(
        _p("finance.view", "مشاهده امور مالی و گزارش‌ها"),
        _p("finance.create", "ثبت درآمد و هزینه"),
        _p("finance.update", "ویرایش تراکنش"),
        _p("finance.delete", "حذف تراکنش"),
        _p("finance.manage", "مدیریت حساب‌ها و دسته‌بندی‌ها"),
    ),
    nav=(NavSpec("finance", "امور مالی", "/finance", "مالی", "finance.view", sort_order=40),),
)


def _planned(code: str, title_fa: str, sort_order: int, depends_on: tuple[str, ...] = ()) -> ModuleSpec:
    return ModuleSpec(code=code, title_fa=title_fa, status="planned", depends_on=depends_on, sort_order=sort_order)


REGISTRY: dict[str, ModuleSpec] = {
    spec.code: spec
    for spec in (
        CORE,
        ATTENDANCE,
        TASKS,
        PERSONNEL,
        PAYROLL,
        CRM,
        _planned("vendors", "فروشندگان و تأمین‌کنندگان", 60),
        FINANCE,
        INVOICING,
        _planned("inventory", "انبار و فروش", 90),
        _planned("monitoring", "منتورینگ", 100),
    )
}


def all_permission_specs() -> dict[str, tuple[ModuleSpec, PermissionSpec]]:
    return {perm.code: (module, perm) for module in REGISTRY.values() for perm in module.permissions}
