from __future__ import annotations

from typing import TYPE_CHECKING

from django.db.models import Q, QuerySet

if TYPE_CHECKING:
    from simorgh.apps.hr_core.models import Employee, EmployeeBankAccount, EmployeeDocument, JobTitle


def job_titles_for_tenant(tenant_id: int) -> QuerySet:
    from simorgh.apps.hr_core.models.employee import JobTitle
    return JobTitle.objects.filter(tenant_id=tenant_id).order_by("title")


def job_title_by_id(tenant_id: int, pk: int) -> "JobTitle | None":
    from simorgh.apps.hr_core.models.employee import JobTitle
    return JobTitle.objects.filter(tenant_id=tenant_id, pk=pk).first()


def employees_for_tenant(
    tenant_id: int,
    *,
    status: str | None = None,
    department_id: int | None = None,
    employment_type: str | None = None,
    manager_id: int | None = None,
    job_title_id: int | None = None,
    search: str | None = None,
) -> QuerySet:
    from simorgh.apps.hr_core.models import Employee

    qs = Employee.objects.filter(tenant_id=tenant_id).select_related(
        "job_title", "department", "manager"
    )
    if status:
        qs = qs.filter(status=status)
    if department_id:
        qs = qs.filter(department_id=department_id)
    if employment_type:
        qs = qs.filter(employment_type=employment_type)
    if manager_id:
        qs = qs.filter(manager_id=manager_id)
    if job_title_id:
        qs = qs.filter(job_title_id=job_title_id)
    if search:
        qs = qs.filter(
            Q(first_name__icontains=search)
            | Q(last_name__icontains=search)
            | Q(display_name__icontains=search)
            | Q(employee_no__icontains=search)
            | Q(work_email__icontains=search)
        )
    return qs.order_by("last_name", "first_name")


def employee_by_public_id(tenant_id: int, public_id: str) -> "Employee | None":
    from simorgh.apps.hr_core.models import Employee
    return (
        Employee.objects.filter(tenant_id=tenant_id, public_id=public_id)
        .select_related("job_title", "department", "manager", "user")
        .first()
    )


def employee_by_pk(tenant_id: int, pk: int) -> "Employee | None":
    from simorgh.apps.hr_core.models import Employee
    return Employee.objects.filter(tenant_id=tenant_id, pk=pk).first()


def direct_reports(employee: "Employee") -> QuerySet:
    from simorgh.apps.hr_core.models import Employee
    return Employee.objects.filter(
        tenant_id=employee.tenant_id, manager=employee
    ).order_by("last_name", "first_name")


def org_chart_tree(tenant_id: int, *, max_depth: int | None = None) -> list[dict]:
    from simorgh.apps.hr_core.models import Employee

    all_employees = list(
        Employee.objects.filter(tenant_id=tenant_id)
        .select_related("job_title", "department")
        .order_by("last_name", "first_name")
    )
    by_manager: dict[int | None, list] = {}
    for emp in all_employees:
        by_manager.setdefault(emp.manager_id, []).append(emp)

    def build_node(emp: Employee, depth: int) -> dict:
        node: dict = {
            "id": emp.pk,
            "public_id": str(emp.public_id),
            "employee_no": emp.employee_no,
            "display_name": str(emp),
            "job_title": emp.job_title.title if emp.job_title else None,
            "department_name": emp.department.name if emp.department else None,
            "status": emp.status,
        }
        if max_depth is None or depth < max_depth:
            node["children"] = [
                build_node(c, depth + 1) for c in by_manager.get(emp.pk, [])
            ]
        else:
            node["children_truncated"] = len(by_manager.get(emp.pk, [])) > 0
        return node

    return [build_node(e, 0) for e in by_manager.get(None, [])]


def documents_for_employee(employee: "Employee") -> QuerySet:
    from simorgh.apps.hr_core.models import EmployeeDocument
    return EmployeeDocument.objects.filter(employee=employee).order_by("-created_at")


def bank_accounts_for_employee(employee: "Employee") -> QuerySet:
    from simorgh.apps.hr_core.models import EmployeeBankAccount
    return EmployeeBankAccount.objects.filter(employee=employee).order_by(
        "-is_default", "bank_name"
    )
