from __future__ import annotations

import json
from pathlib import Path


EDITABLE_MODULE_KEYS = [
    "dashboard",
    "purchase_order",
    "costing",
    "production",
    "qa",
    "finance",
    "tool",
    "setting",
    "bom",
    "tech_pack",
    "samples",
    "hr",
    "history",
]

ACTIONS_BY_MODULE = {
    "dashboard": [],
    "purchase_order": [
        "action.purchase_order.import_pdf",
        "action.purchase_order.import_folder",
        "action.purchase_order.export_report",
        "action.purchase_order.delete_po",
        "action.purchase_order.edit_po",
        "action.purchase_order.compare_po",
        "action.purchase_order.approve",
    ],
    "costing": [
        "action.costing.import_pdf",
        "action.costing.import_ws",
        "action.costing.import_folder",
        "action.costing.export_report",
        "action.costing.adjust_crop",
        "action.costing.delete_style",
        "action.costing.edit_row",
        "action.costing.collection_list",
        "action.costing.approve",
    ],
    "production": [
        "action.production.edit",
        "action.production.delete",
        "action.production.export_report",
        "action.production.packing_list",
        "action.production.factory_list",
    ],
    "qa": [],
    "finance": [],
    "tool": [
        "action.tool.report_builder",
        "action.tool.download_tech_pack",
    ],
    "setting": [
        "action.setting.save_online_setup",
        "action.setting.test_connection",
        "action.setting.check_updates",
        "action.setting.save_mail_settings",
        "action.setting.send_test_email",
    ],
    "bom": [
        "action.bom.new",
        "action.bom.copy",
        "action.bom.edit",
        "action.bom.delete",
        "action.bom.export_report",
        "action.bom.generate_from_tech_pack",
        "action.bom.import_fds",
        "action.bom.approve",
        "action.bom.supplier_list",
        "action.bom.supplier_add",
        "action.bom.supplier_edit",
        "action.bom.supplier_delete",
    ],
    "tech_pack": [
        "action.tech_pack.import_pdf",
        "action.tech_pack.import_folder",
        "action.tech_pack.export_report",
        "action.tech_pack.delete_style",
        "action.tech_pack.edit_style",
        "action.tech_pack.detail_edit",
        "action.tech_pack.detail_save",
        "action.consumption.approve",
    ],
    "samples": [
        "action.samples.new",
        "action.samples.copy",
        "action.samples.import_report",
        "action.samples.export_report",
        "action.samples.delete",
        "action.samples.edit",
    ],
    "hr": [
        "action.hr.manage_shared_lists",
        "action.hr.employee.new",
        "action.hr.employee.edit",
        "action.hr.employee.delete",
        "action.hr.employee.toggle_active",
        "action.hr.attendance.new",
        "action.hr.attendance.delete",
        "action.hr.attendance.quick",
        "action.hr.attendance.overview",
        "action.hr.attendance.check_in",
        "action.hr.attendance.check_out",
        "action.hr.attendance.edit",
        "action.hr.export_report",
    ],
    "history": [],
}

ACTION_KEYS = [action_key for group in ACTIONS_BY_MODULE.values() for action_key in group]

DEFAULT_ROLE_DEFAULTS = {
    "admin": {
        "modules": {
            "dashboard": True,
            "purchase_order": True,
            "costing": True,
            "production": True,
            "qa": True,
            "finance": True,
            "tool": True,
            "setting": True,
            "bom": True,
            "tech_pack": True,
            "samples": True,
            "hr": True,
            "history": True,
        },
        "actions": {action_key: True for action_key in ACTION_KEYS},
    },
    "moderate": {
        "modules": {
            "dashboard": True,
            "purchase_order": True,
            "costing": True,
            "production": True,
            "qa": True,
            "finance": True,
            "tool": True,
            "setting": True,
            "bom": True,
            "tech_pack": True,
            "samples": True,
            "hr": True,
            "history": True,
        },
        "actions": {action_key: True for action_key in ACTION_KEYS},
    },
    "user": {
        "modules": {
            "dashboard": True,
            "purchase_order": True,
            "costing": True,
            "production": True,
            "qa": True,
            "finance": True,
            "tool": True,
            "setting": False,
            "bom": True,
            "tech_pack": True,
            "samples": True,
            "hr": True,
            "history": True,
        },
        "actions": {
            "action.purchase_order.import_pdf": True,
            "action.purchase_order.import_folder": False,
            "action.purchase_order.export_report": True,
            "action.purchase_order.delete_po": False,
            "action.purchase_order.edit_po": False,
            "action.purchase_order.compare_po": False,
            "action.purchase_order.approve": False,
            "action.costing.import_pdf": True,
            "action.costing.import_ws": True,
            "action.costing.import_folder": False,
            "action.costing.export_report": True,
            "action.costing.adjust_crop": False,
            "action.costing.delete_style": False,
            "action.costing.edit_row": False,
            "action.costing.collection_list": False,
            "action.costing.approve": False,
            "action.production.edit": True,
            "action.production.delete": False,
            "action.production.export_report": True,
            "action.production.packing_list": True,
            "action.production.factory_list": True,
            "action.tool.report_builder": True,
            "action.tool.download_tech_pack": False,
            "action.bom.new": True,
            "action.bom.copy": True,
            "action.bom.edit": True,
            "action.bom.delete": False,
            "action.bom.export_report": True,
            "action.bom.generate_from_tech_pack": True,
            "action.bom.import_fds": True,
            "action.bom.approve": False,
            "action.bom.supplier_list": True,
            "action.bom.supplier_add": True,
            "action.bom.supplier_edit": True,
            "action.bom.supplier_delete": False,
            "action.tech_pack.import_pdf": True,
            "action.tech_pack.import_folder": False,
            "action.tech_pack.export_report": True,
            "action.tech_pack.delete_style": False,
            "action.tech_pack.edit_style": False,
            "action.tech_pack.detail_edit": False,
            "action.tech_pack.detail_save": False,
            "action.consumption.approve": False,
            "action.samples.new": True,
            "action.samples.copy": True,
            "action.samples.import_report": True,
            "action.samples.export_report": True,
            "action.samples.delete": False,
            "action.samples.edit": True,
            "action.hr.employee.new": False,
            "action.hr.employee.edit": False,
            "action.hr.employee.delete": False,
            "action.hr.employee.toggle_active": False,
            "action.hr.attendance.new": False,
            "action.hr.attendance.delete": False,
            "action.hr.attendance.quick": False,
            "action.hr.attendance.overview": True,
            "action.hr.attendance.check_in": True,
            "action.hr.attendance.check_out": True,
            "action.hr.attendance.edit": False,
            "action.hr.export_report": True,
            "action.hr.manage_shared_lists": False,
            "action.setting.save_online_setup": False,
            "action.setting.test_connection": False,
            "action.setting.check_updates": False,
            "action.setting.save_mail_settings": False,
            "action.setting.send_test_email": False,
        },
    },
}


def _normalize_permissions_block(payload: dict | None, base: dict) -> dict:
    source = payload if isinstance(payload, dict) else {}
    modules_payload = source.get("modules", {}) if isinstance(source.get("modules", {}), dict) else {}
    actions_payload = source.get("actions", {}) if isinstance(source.get("actions", {}), dict) else {}
    legacy_action_aliases = {
        "action.hr.manage_shared_lists": "action.setting.manage_shared_lists",
    }
    normalized_modules = {
        key: bool(modules_payload.get(key, default_value))
        for key, default_value in base["modules"].items()
    }
    normalized_actions = {
        key: bool(actions_payload.get(key, actions_payload.get(legacy_action_aliases.get(key, ""), default_value)))
        for key, default_value in base["actions"].items()
    }
    return {
        "modules": normalized_modules,
        "actions": normalized_actions,
    }


def normalize_permission_settings(payload: dict | None) -> dict:
    source = payload if isinstance(payload, dict) else {}

    if "role_defaults" in source or "user_overrides" in source:
        role_source = source.get("role_defaults", {})
        overrides_source = source.get("user_overrides", {})
    else:
        # Backward compatibility with older schema that stored roles at the top level.
        role_source = source
        overrides_source = {}

    role_defaults = {
        role: _normalize_permissions_block(role_source.get(role, {}), DEFAULT_ROLE_DEFAULTS[role])
        for role in ("admin", "moderate", "user")
    }

    normalized_overrides: dict[str, dict] = {}
    if isinstance(overrides_source, dict):
        for email, override_payload in overrides_source.items():
            email_key = str(email).strip().lower()
            if not email_key:
                continue
            role_hint = str(override_payload.get("role_hint", "user")).strip().lower()
            if role_hint == "admin":
                normalized_role_hint = "admin"
            elif role_hint == "moderate":
                normalized_role_hint = "moderate"
            else:
                normalized_role_hint = "user"
            base = DEFAULT_ROLE_DEFAULTS[normalized_role_hint]
            normalized_overrides[email_key] = {
                "role_hint": normalized_role_hint,
                **_normalize_permissions_block(override_payload, base),
            }

    return {
        "role_defaults": role_defaults,
        "user_overrides": normalized_overrides,
    }


def load_permission_settings(path: Path) -> dict:
    if not path.exists():
        return normalize_permission_settings(None)
    try:
        payload = json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        payload = {}
    return normalize_permission_settings(payload)


def save_permission_settings(path: Path, payload: dict) -> dict:
    normalized = normalize_permission_settings(payload)
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(normalized, ensure_ascii=False, indent=2), encoding="utf-8")
    return normalized


def get_role_default_map(settings: dict, role: str) -> dict[str, bool]:
    normalized = normalize_permission_settings(settings)
    role_key = str(role or "user").strip().lower()
    if role_key not in DEFAULT_ROLE_DEFAULTS:
        role_key = "user"
    role_payload = normalized["role_defaults"][role_key]
    permission_map: dict[str, bool] = {}
    for module_key, allowed in role_payload["modules"].items():
        permission_map[f"module.{module_key}"] = bool(allowed)
    for action_key, allowed in role_payload["actions"].items():
        permission_map[action_key] = bool(allowed)
    return permission_map


def get_user_override(settings: dict, email: str) -> dict:
    normalized = normalize_permission_settings(settings)
    return dict(normalized["user_overrides"].get(str(email or "").strip().lower(), {}))


def get_effective_permission_map(settings: dict, role: str, email: str) -> dict[str, bool]:
    permission_map = get_role_default_map(settings, role)
    override = get_user_override(settings, email)
    for module_key, allowed in dict(override.get("modules", {})).items():
        permission_map[f"module.{module_key}"] = bool(allowed)
    for action_key, allowed in dict(override.get("actions", {})).items():
        permission_map[action_key] = bool(allowed)
    return permission_map
