from datetime import datetime, time, timedelta
from decimal import Decimal

from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.utils import timezone

from apps.attendance.models import AttendanceDevice, AttendanceRecord, DeviceEmployeeMap
from apps.employees.models import Employee
from apps.leave.models import LeaveBalance, LeaveType
from apps.organization.models import Branch, Company, Department, Designation, Shift
from apps.payroll.models import EmployeeSalaryAssignment, SalaryComponent, SalaryStructure, SalaryStructureLine


class Command(BaseCommand):
    help = "Create clearly marked Local UAT sample employees, salaries, leave balances and FO-M1 mappings."

    def handle(self, *args, **options):
        company = Company.objects.get(code="SHOHOJ")
        branch = Branch.objects.get(company=company, code="HO")
        shift = Shift.objects.get(company=company, code="GEN")
        structure, _ = SalaryStructure.objects.get_or_create(
            company=company, code="UAT-STAFF", defaults={"name": "UAT Sample Staff"}
        )
        basic_component = SalaryComponent.objects.get(company=company, code="BASIC")
        house_component = SalaryComponent.objects.get(company=company, code="HOUSE")
        SalaryStructureLine.objects.update_or_create(
            structure=structure, component=basic_component,
            defaults={"amount": Decimal("0.00"), "percentage": Decimal("0.00"), "formula": ""},
        )
        SalaryStructureLine.objects.update_or_create(
            structure=structure, component=house_component,
            defaults={"amount": Decimal("0.00"), "percentage": Decimal("0.00"), "formula": "GROSS-BASIC"},
        )
        device = AttendanceDevice.objects.filter(company=company, branch=branch, model__iexact="FO-M1").first()

        rows = [
            ("SSCL-001", "Aminul Islam", "HR", "HRE", Decimal("45000"), Decimal("25000"), False, "101"),
            ("SSCL-002", "Nusrat Jahan", "ACC", "ACCO", Decimal("42000"), Decimal("24000"), False, "102"),
            ("SSCL-003", "Rakib Hasan", "PROD", "PRODO", Decimal("36000"), Decimal("20000"), True, "103"),
            ("SSCL-004", "Sadia Akter", "SALES", "SALESE", Decimal("38000"), Decimal("21000"), True, "104"),
        ]
        today = timezone.localdate()
        join_date = today - timedelta(days=365)
        created = 0
        for code, name, dept_code, desig_code, gross, basic, ot_ok, device_uid in rows:
            dept = Department.objects.get(company=company, code=dept_code)
            desig = Designation.objects.get(company=company, code=desig_code)
            employee, was_created = Employee.objects.get_or_create(
                company=company,
                employee_code=code,
                defaults={
                    "full_name": name,
                    "branch": branch,
                    "department": dept,
                    "designation": desig,
                    "shift": shift,
                    "joining_date": join_date,
                    "status": Employee.Status.ACTIVE,
                    "ot_eligible": ot_ok,
                    "weekly_holiday": "Friday",
                },
            )
            if was_created:
                created += 1
            EmployeeSalaryAssignment.objects.get_or_create(
                employee=employee,
                effective_from=join_date,
                defaults={
                    "structure": structure,
                    "gross_salary": gross,
                    "basic_salary": basic,
                    "ot_eligible": ot_ok,
                    "ot_rate_multiplier": Decimal("2.00") if ot_ok else Decimal("1.00"),
                    "notes": "Local UAT sample salary assignment",
                },
            )
            for lt in LeaveType.objects.filter(company=company, code__in=["CL", "SL", "AL"]):
                LeaveBalance.objects.get_or_create(
                    employee=employee,
                    leave_type=lt,
                    year=today.year,
                    defaults={"opening": 0, "allocated": lt.yearly_allocation, "used": 0, "adjusted": 0},
                )
            if device:
                DeviceEmployeeMap.objects.get_or_create(
                    device=device, employee=employee,
                    defaults={"device_user_id": device_uid, "is_active": True},
                )
            # Two recent sample days; include complete punches so the default
            # missing-punch policy does not create artificial UAT blockers.
            for offset, status in [(2, AttendanceRecord.Status.PRESENT), (1, AttendanceRecord.Status.LATE if code == "SSCL-003" else AttendanceRecord.Status.PRESENT)]:
                work_date = today - timedelta(days=offset)
                check_in_clock = time(9, 20) if status == AttendanceRecord.Status.LATE else time(9, 0)
                check_in = timezone.make_aware(datetime.combine(work_date, check_in_clock), timezone.get_current_timezone())
                check_out = timezone.make_aware(datetime.combine(work_date, time(18, 0)), timezone.get_current_timezone())
                AttendanceRecord.objects.update_or_create(
                    employee=employee, work_date=work_date,
                    defaults={
                        "check_in": check_in,
                        "check_out": check_out,
                        "worked_minutes": 480,
                        "late_minutes": 10 if status == AttendanceRecord.Status.LATE else 0,
                        "status": status,
                        "remarks": "Local UAT sample record",
                    },
                )
        # Create predictable LOCAL-UAT-only role accounts so maintainers can test permissions.
        # These are never intended for production. The installation guide requires changing/removing them before go-live.
        User = get_user_model()
        from apps.accounts.models import UserCompanyAccess
        demo_password = "UAT-ChangeMe-2026!"
        employees_by_code = {e.employee_code: e for e in Employee.objects.filter(company=company, employee_code__startswith="SSCL-")}
        demo_accounts = [
            ("uat.hr", "UAT HR Admin", "HR Admin", "SSCL-001"),
            ("uat.accounts", "UAT Accounts", "Accounts", "SSCL-002"),
            ("uat.employee", "UAT Employee", "Employee", "SSCL-003"),
            ("uat.employee2", "UAT Employee 2", "Employee", "SSCL-004"),
            ("uat.payroll", "UAT Payroll Officer", "Payroll Officer", None),
            ("uat.it", "UAT IT", "IT", None),
        ]
        for username, display_name, role_name, employee_code in demo_accounts:
            user, user_created = User.objects.get_or_create(username=username, defaults={"display_name": display_name})
            if user_created:
                user.set_password(demo_password)
                user.force_password_change = False
                user.save(update_fields=["password", "force_password_change", "updated_at"])
            group = Group.objects.filter(name=role_name).first()
            if group:
                user.groups.add(group)
            UserCompanyAccess.objects.update_or_create(
                user=user, company=company, defaults={"is_active": True, "is_default": True}
            )
            if employee_code:
                employee = employees_by_code.get(employee_code)
                if employee and employee.user_id != user.pk:
                    employee.user = user
                    employee.save(update_fields=["user", "updated_at"])

        # Use SSCL-001 as the sample reporting manager so manager/approval scope can be exercised.
        manager = employees_by_code.get("SSCL-001")
        if manager:
            manager_user = manager.user
            manager_group = Group.objects.filter(name="Manager").first()
            if manager_user and manager_group:
                manager_user.groups.add(manager_group)
            for code in ("SSCL-003", "SSCL-004"):
                employee = employees_by_code.get(code)
                if employee and employee.reporting_manager_id != manager.pk:
                    employee.reporting_manager = manager
                    employee.save(update_fields=["reporting_manager", "updated_at"])

        self.stdout.write(self.style.SUCCESS(f"Local UAT sample data ready. New employees created: {created}."))
        self.stdout.write("FO-M1 sample device IDs: SSCL-001→101, SSCL-002→102, SSCL-003→103, SSCL-004→104")
        self.stdout.write("LOCAL-UAT role users: uat.hr, uat.accounts, uat.employee, uat.employee2, uat.payroll, uat.it")
        self.stdout.write("LOCAL-UAT password (trial only): UAT-ChangeMe-2026!")
