# commands/bootstrap.py
from __future__ import annotations

from datetime import date, datetime
from typing import Optional, Dict, Any, List

import click
from flask.cli import with_appcontext

from extensions import db
from models import (
    Department, Designation, Role, Employee,
    Menu, SubMenu, RoleAccess
)

# ---------- Admin seed ----------
DEFAULT_ADMIN = {
    "employee_code": "ADM001",
    "full_name": "System Administrator",
    "email": "admin@company.com",
    "phone": "9999999999",
    "date_of_joining": date.today(),
    "password": "Admin@123",  # change this after login
    "location": "Head Office",
}
DEFAULT_DEPARTMENT = "Administration"
DEFAULT_DESIGNATION = "Administrator"
DEFAULT_ROLE = "admin"

# ---------- Menus (new structure) ----------
# Using the sequence you shared; feel free to tweak 'order'
MENUS = [
    {"name": "Dashboard",      "icon": "bi-speedometer2",       "order": 1},
    {"name": "Admin Tools",    "icon": "bi-tools",              "order": 2},
    {"name": "Induction",      "icon": "bi bi-person-add",      "order": 3},
    {"name": "Employee",       "icon": "bi-person-circle",      "order": 4},
    {"name": "Attendance",     "icon": "bi-calendar-event",     "order": 5},
    {"name": "Leaves",         "icon": "bi bi-calendar2-heart", "order": 6},
    {"name": "My Salary",      "icon": "bi-cash-coin",          "order": 7},
    {"name": "Payroll",        "icon": "bi-cash-coin",          "order": 8},
    {"name": "Setup Tools",    "icon": "bi-tools",              "order": 9},
    {"name": "Broadcast",      "icon": "bi-megaphone-fill",     "order": 10},
    {"name": "Logs",           "icon": "bi-clipboard-data",     "order": 11},
    {"name": "Exit Process",   "icon": "bi-person-x",           "order": 12},
    {"name": "Feedback",       "icon": "bi bi-flag-fill",       "order": 13},
    {"name": "Imp Documents",  "icon": "bi bi-file-earmark-pdf","order": 14},
    {"name": "My Profile",     "icon": "bi-person-circle",      "order": 15},
    {"name": "Reimbursements", "icon": "bi-cash-coin",          "order": 16},
]

# ---------- SubMenus (new structure) ----------
# Map each submenu to its parent menu by NAME
SUBMENUS = [
    # Dashboard
    {"menu": "Dashboard", "name": "Dashboard", "url": "/", "endpoint": "dashboard_bp.index", "order": 1},
    {"menu": "Dashboard", "name": "Executive Dashboard", "url": "/dashboard/executive", "endpoint": "dashboard_bp.executive_dashboard", "order": 2},

    # Admin Tools
    {"menu": "Admin Tools", "name": "Access Control",        "url": "/admin/access-control",      "endpoint": None,                         "order": 1},
    {"menu": "Admin Tools", "name": "Menu Management",       "url": "/admin/menu-management",     "endpoint": None,                         "order": 2},
    {"menu": "Admin Tools", "name": "Auto Route",            "url": "/admin/route-discovery",     "endpoint": "admin.route_discovery",      "order": 3},
    {"menu": "Admin Tools", "name": "Specific User Access",  "url": "/admin/user-access",         "endpoint": "admin.user_access",          "order": 4},

    # Induction
    {"menu": "Induction", "name": "Employee Onboard Link", "url": "/employee/admin/public-links", "endpoint": "employee.list_public_links",   "order": 1},
    {"menu": "Induction", "name": "Onboarding Approval",   "url": "/employee/pending-approvals",  "endpoint": "employee.view_pending_employees", "order": 2},

    # Employee
    {"menu": "Employee", "name": "View Employees",        "url": "/employee/view",               "endpoint": "employee.view_employees",        "order": 1},
    {"menu": "Employee", "name": "Assign Salary",         "url": "/payroll/salary-structure",    "endpoint": "payroll.salary_structure",       "order": 2},
    {"menu": "Employee", "name": "Salary Overview",       "url": "/payroll/salary-structures",   "endpoint": "payroll.view_salary_structures", "order": 3},
    {"menu": "Employee", "name": "Employee Documents",    "url": "/documents/employee-repository","endpoint": "documents.employee_repository",  "order": 4},
    {"menu": "Employee", "name": "Team Attendance",       "url": "/employee/team-attendance",    "endpoint": "employee.team_attendance",       "order": 5},
    {"menu": "Employee", "name": "Import Employees",      "url": "/employee/import-employees",   "endpoint": "employee.import_employees",      "order": 6},
    {"menu": "Employee", "name": "Upload Emp docs",       "url": "/docs/upload",                 "endpoint": "docs.upload_document",           "order": 7},
    {"menu": "Employee", "name": "Emp Company Doc",       "url": "/docs/",                       "endpoint": "docs.list_documents",            "order": 8},

    # Attendance
    {"menu": "Attendance", "name": "Attendance Overview", "url": "/attendance/calendar",         "endpoint": "attendance.view_calendar",       "order": 1},
    {"menu": "Attendance", "name": "Month-wise Attendance","url": "/attendance/monthly-summary", "endpoint": "attendance_monthly_summary",     "order": 2},
    {"menu": "Attendance", "name": "Desktime Logs",       "url": "/desktime/logs",               "endpoint": None,                             "order": 3},

    # Leaves
    {"menu": "Leaves", "name": "Apply for Leave",      "url": "/leave/apply",            "endpoint": "leave.apply_leave",            "order": 1},
    {"menu": "Leaves", "name": "My Leave History",     "url": "/leave/history",          "endpoint": "leave.view_history",           "order": 2},
    {"menu": "Leaves", "name": "HOD Pending Requests", "url": "/leave/manager/pending",  "endpoint": "leave.manager_pending",         "order": 3},
    {"menu": "Leaves", "name": "HR Pending Requests",  "url": "/leave/hr/pending",       "endpoint": "leave.hr_pending",              "order": 4},
    {"menu": "Leaves", "name": "Balance Report",       "url": "/leave/balance-report",   "endpoint": None,                            "order": 5},
    {"menu": "Leaves", "name": "Apply Comp Off",       "url": "/leave/comp-off/apply",   "endpoint": "leave.apply_comp_off",          "order": 6},
    {"menu": "Leaves", "name": "Pending Comp Off",     "url": "/leave/comp-off/pending", "endpoint": "leave.pending_comp_off",         "order": 7},

    # My Salary
    {"menu": "My Salary", "name": "My Salary Slips",   "url": "/payroll/my-salary-slips","endpoint": "payroll.my_salary_slips",        "order": 1},
    {"menu": "My Salary", "name": "Preview Salary Slip","url": "/payroll/preview-slip",  "endpoint": "payroll.preview_salary_slip",    "order": 2},

    # Payroll
    {"menu": "Payroll", "name": "Process Payroll",     "url": "/payroll/process-payroll-preview", "endpoint": "payroll.process_payroll_preview",  "order": 1},
    {"menu": "Payroll", "name": "Payroll Summary",     "url": "/payroll/payroll-summary",         "endpoint": "payroll.payroll_summary",          "order": 2},  # fixed URL
    {"menu": "Payroll", "name": "Consolidated Salary", "url": "/payroll/payroll/consolidated-view","endpoint": "payroll.consolidated_salary_view", "order": 3},

    # Setup Tools
    {"menu": "Setup Tools", "name": "Leave Types",            "url": "/leave/leave-types",           "endpoint": "leave.view_leave_types",        "order": 1},
    {"menu": "Setup Tools", "name": "Leave Policies",         "url": "/leave/leave-policies",        "endpoint": "leave.view_leave_policies",     "order": 2},
    {"menu": "Setup Tools", "name": "Holiday & RH Config",    "url": "/leave/holidays",              "endpoint": "leave.view_holidays",           "order": 3},
    {"menu": "Setup Tools", "name": "Weekend Settings",       "url": "/attendance/weekend-settings", "endpoint": "attendance.weekend_settings",   "order": 4},
    {"menu": "Setup Tools", "name": "Department Master",      "url": "/master/department",           "endpoint": None,                             "order": 5},
    {"menu": "Setup Tools", "name": "Designation Master",     "url": "/master/designation",          "endpoint": None,                             "order": 6},
    {"menu": "Setup Tools", "name": "Manage Salary Components","url": "/payroll/manage-components",  "endpoint": "payroll.manage_components",      "order": 7},
    {"menu": "Setup Tools", "name": "Salary Formula",         "url": "/payroll/salary-formula",      "endpoint": "payroll.salary_formula",         "order": 8},
    {"menu": "Setup Tools", "name": "Leave Balance Allocation","url": "/leave/allocation",           "endpoint": "leave.leave_allocation",         "order": 9},
    {"menu": "Setup Tools", "name": "Allocation Batches",     "url": "/leave/allocation/batches",     "endpoint": "leave.allocation_batches",       "order": 10},
    {"menu": "Setup Tools", "name": "Set Leave Balance",      "url": "/leave/balance/set",            "endpoint": "leave.balance_set_form",         "order": 11},
    {"menu": "Setup Tools", "name": "Manage Roles",           "url": "/auth/manage-roles",            "endpoint": "auth.manage_roles",              "order": 12},

    # Broadcast
    {"menu": "Broadcast", "name": "Manage Broadcast",  "url": "/broadcast/broadcasts",      "endpoint": "broadcast.manage_broadcasts",     "order": 1},
    {"menu": "Broadcast", "name": "Announcements",     "url": "/broadcast/announcements",   "endpoint": None,                              "order": 2},

    # Logs
    {"menu": "Logs", "name": "Employee Logs",          "url": "/employee/logs",             "endpoint": "employee.view_change_log",        "order": 1},
    {"menu": "Logs", "name": "Master Logs",            "url": "/master/master/logs",         "endpoint": "master.view_master_logs",         "order": 2},
    {"menu": "Logs", "name": "Approval Logs",          "url": "/employee/approval-logs",     "endpoint": "employee.view_approval_logs",     "order": 3},
    {"menu": "Logs", "name": "Email Logs",             "url": "/admin/email/logs",           "endpoint": "admin_email_logs.logs",           "order": 4},

    # Exit Process
    {"menu": "Exit Process", "name": "Initiate Exit (HR)", "url": "/exit/new",           "endpoint": "exit.create_exit",        "order": 1},
    {"menu": "Exit Process", "name": "All Exits",          "url": "/exit/list",          "endpoint": "exit_list.list_all",      "order": 2},
    {"menu": "Exit Process", "name": "HOD Exit Approval",  "url": "/exit/approvals",     "endpoint": "exit_list.approvals_queue","order": 3},
    {"menu": "Exit Process", "name": "Handover for me",    "url": "/exit/acks",          "endpoint": "exit_list.acks_queue",    "order": 4},
    {"menu": "Exit Process", "name": "IT Exit Clearance",  "url": "/exit/it",            "endpoint": "exit_list.it_queue",      "order": 5},
    {"menu": "Exit Process", "name": "My Exits",           "url": "/exit/mine",          "endpoint": "exit_list.my_exits",      "order": 6},
    {"menu": "Exit Process", "name": "Exit Handover",      "url": "/exit/mine",          "endpoint": None,                      "order": 7},

    # Feedback
    {"menu": "Feedback", "name": "Manage Feedback",         "url": "/admin/feedback/questions", "endpoint": "feedback_admin.list_questions",     "order": 1},
    {"menu": "Feedback", "name": "Submitted Feedback",      "url": "/feedback/view-submitted-feedback", "endpoint": "feedback.view_submitted_feedback", "order": 2},

    # Imp Documents
    {"menu": "Imp Documents", "name": "Document Management","url": "/documents/document-management", "endpoint": "document.document_management", "order": 1},
    {"menu": "Imp Documents", "name": "View Documents",     "url": "/documents/view-documents",      "endpoint": "documents.view_documents",    "order": 2},

    # My Profile
    {"menu": "My Profile", "name": "My Profile",          "url": "/employee/me/profile", "endpoint": "employee.my_profile",    "order": 1},
    {"menu": "My Profile", "name": "Issued Documents",    "url": "/docs/my",             "endpoint": "docs.my_documents",      "order": 2},

    # Reimbursements
    {"menu": "Reimbursements", "name": "New TR Request",  "url": "/travel/request/new",  "endpoint": "tr.tr_new",     "order": 1},
    {"menu": "Reimbursements", "name": "HOD TR Approval", "url": "/travel/hod/pending",  "endpoint": "tr.hod_pending","order": 2},
    {"menu": "Reimbursements", "name": "HR TR Approval",  "url": "/travel/hr/pending",   "endpoint": "tr.hr_pending", "order": 3},
    {"menu": "Reimbursements", "name": "My TR Requests",  "url": "/travel/my",           "endpoint": "tr.tr_my",      "order": 4},
]

# ---------- helpers ----------
def _get_or_create(model, unique_filter: Dict[str, Any], defaults: Optional[Dict[str, Any]] = None):
    obj = model.query.filter_by(**unique_filter).first()
    if obj:
        # keep idempotent: update small attributes if changed
        if defaults:
            changed = False
            for k, v in defaults.items():
                if getattr(obj, k) != v:
                    setattr(obj, k, v)
                    changed = True
            if changed:
                db.session.add(obj)
        return obj, False
    data = dict(unique_filter)
    if defaults:
        data.update(defaults)
    obj = model(**data)
    db.session.add(obj)
    return obj, True

def _ensure_masters():
    dept, _ = _get_or_create(Department, {"name": DEFAULT_DEPARTMENT})
    desig, _ = _get_or_create(Designation, {"title": DEFAULT_DESIGNATION})
    role, _ = _get_or_create(Role, {"name": DEFAULT_ROLE}, {"description": "Full administrative access"})
    db.session.flush()
    return dept, desig, role

def _ensure_admin_user(dept: Department, desig: Designation, role: Role):
    emp = Employee.query.filter_by(email=DEFAULT_ADMIN["email"]).first()
    if not emp:
        emp = Employee(
            employee_code=DEFAULT_ADMIN["employee_code"],
            full_name=DEFAULT_ADMIN["full_name"],
            email=DEFAULT_ADMIN["email"],
            phone=DEFAULT_ADMIN["phone"],
            date_of_joining=DEFAULT_ADMIN["date_of_joining"],
            location=DEFAULT_ADMIN["location"],
            department_id=dept.id,
            designation_id=desig.id,
            role_id=role.id,
            status="active",
            created_on=datetime.utcnow(),
        )
        emp.set_password(DEFAULT_ADMIN["password"])
        db.session.add(emp)
        click.echo(f"👤 Created admin: {emp.email} / {DEFAULT_ADMIN['password']}")
    else:
        changed = False
        if emp.role_id != role.id:
            emp.role_id = role.id; changed = True
        if not emp.department_id: emp.department_id = dept.id; changed = True
        if not emp.designation_id: emp.designation_id = desig.id; changed = True
        if not emp.password_hash:
            emp.set_password(DEFAULT_ADMIN["password"]); changed = True
        if changed:
            click.echo(f"🔧 Updated admin mappings for {emp.email}")
    db.session.flush()
    return emp

def _ensure_menus() -> Dict[str, int]:
    m = {}
    for row in MENUS:
        menu, _ = _get_or_create(
            Menu,
            {"name": row["name"]},
            {"icon": row.get("icon"), "order": row.get("order", 0)},
        )
        db.session.flush()
        m[menu.name] = menu.id
    return m

def _ensure_submenus(menu_map: Dict[str, int]) -> List[int]:
    created_ids: List[int] = []
    for sm in SUBMENUS:
        parent_id = menu_map.get(sm["menu"])
        if not parent_id:
            click.echo(f"⚠️ Skipping '{sm['name']}' — parent '{sm['menu']}' not found")
            continue
        unique = {"name": sm["name"], "menu_id": parent_id}
        defaults = {
            "url": sm["url"],
            "endpoint": sm.get("endpoint"),
            "order": sm.get("order", 0),
        }
        sub, _ = _get_or_create(SubMenu, unique, defaults)
        db.session.flush()
        created_ids.append(sub.id)
    return created_ids

def _grant_admin_access(submenu_ids: List[int], role_name: str = DEFAULT_ROLE):
    for sid in submenu_ids:
        if not RoleAccess.query.filter_by(role=role_name, submenu_id=sid).first():
            db.session.add(RoleAccess(role=role_name, submenu_id=sid))

@click.command("bootstrap-empty")
@with_appcontext
def bootstrap_empty():
    """
    New environment bootstrap:
    - (Optionally) drop & recreate schema
    - Seed admin role/user
    - Seed Menus/SubMenus exactly as defined above
    - Grant admin access to ALL submenus
    """
    click.echo("🚀 HRMS Bootstrap (admin + menus)")

    if click.confirm("Drop & recreate ALL tables first? (new setup only)", default=False):
        db.drop_all()
        db.create_all()
        click.echo("🧱 Fresh schema created.")

    dept, desig, role = _ensure_masters()
    _ensure_admin_user(dept, desig, role)
    menu_map = _ensure_menus()
    submenu_ids = _ensure_submenus(menu_map)
    _grant_admin_access(submenu_ids)
    db.session.commit()
    click.echo("✅ Done. Login with admin and change the password immediately.")