"""Phase 5.9 — Payroll API."""
from __future__ import annotations

from datetime import date
from decimal import Decimal
from uuid import UUID

from fastapi import APIRouter, Depends, status
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_db, require_tenant
from app.core.security import get_current_user
from app.models.payroll import Department, Employee, EmploymentContract, PayrollPeriod, SalaryComponent
from app.models.types import EmploymentStatus, PayrollPeriodStatus
from app.repositories.base import TenantBaseRepository
from app.services.payroll_service import PayrollAccountingService
from shared.security import CurrentUser

router = APIRouter()


class DepartmentCreate(BaseModel):
    code: str
    name: str


class EmployeeCreate(BaseModel):
    employee_code: str
    first_name: str
    last_name: str
    department_id: UUID | None = None
    base_salary: Decimal = Decimal("0")
    hire_date: date | None = None


class PayrollPeriodCreate(BaseModel):
    name: str
    start_date: date
    end_date: date


class CalculatePayrollRequest(BaseModel):
    payroll_period_id: UUID
    employee_id: UUID


class PostPayrollRequest(BaseModel):
    profile_id: UUID | None = None


class DepartmentRepo(TenantBaseRepository[Department]):
    model = Department


class EmployeeRepo(TenantBaseRepository[Employee]):
    model = Employee


class PayrollPeriodRepo(TenantBaseRepository[PayrollPeriod]):
    model = PayrollPeriod


@router.post("/departments", status_code=status.HTTP_201_CREATED)
async def create_department(
    body: DepartmentCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    repo = DepartmentRepo(db)
    entity = Department(tenant_id=tenant_id, **body.model_dump())
    await repo.add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.get("/departments")
async def list_departments(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    deps = await DepartmentRepo(db).list_by_tenant(tenant_id, limit=100)
    return [{"id": str(d.id), "code": d.code, "name": d.name} for d in deps]


@router.post("/employees", status_code=status.HTTP_201_CREATED)
async def create_employee(
    body: EmployeeCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    repo = EmployeeRepo(db)
    entity = Employee(tenant_id=tenant_id, employment_status=EmploymentStatus.ACTIVE, **body.model_dump())
    await repo.add(entity)
    await db.commit()
    return {"id": str(entity.id), "employee_code": entity.employee_code}


@router.get("/employees")
async def list_employees(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    repo = EmployeeRepo(db)
    employees = await repo.list_by_tenant(tenant_id, limit=100)
    return [{"id": str(e.id), "code": e.employee_code, "name": f"{e.first_name} {e.last_name}"} for e in employees]


@router.post("/periods", status_code=status.HTTP_201_CREATED)
async def create_payroll_period(
    body: PayrollPeriodCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    repo = PayrollPeriodRepo(db)
    entity = PayrollPeriod(tenant_id=tenant_id, status=PayrollPeriodStatus.OPEN, **body.model_dump())
    await repo.add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.get("/periods")
async def list_payroll_periods(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    periods = await PayrollPeriodRepo(db).list_by_tenant(tenant_id, limit=100)
    return [
        {
            "id": str(p.id),
            "name": p.name,
            "start_date": p.start_date.isoformat(),
            "end_date": p.end_date.isoformat(),
            "status": p.status.value,
        }
        for p in periods
    ]


@router.post("/calculate")
async def calculate_payroll(
    body: CalculatePayrollRequest,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    svc = PayrollAccountingService(db)
    payroll = await svc.calculate_payroll(tenant_id, body.payroll_period_id, body.employee_id)
    await db.commit()
    return {
        "id": str(payroll.id),
        "gross_salary": str(payroll.gross_salary),
        "net_salary": str(payroll.net_salary),
        "status": payroll.status.value,
    }


@router.post("/payrolls/{payroll_id}/post")
async def post_payroll(
    payroll_id: UUID,
    body: PostPayrollRequest,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(get_current_user),
):
    from app.models.types import PayrollStatus
    from app.services.payroll_service import PayrollRepo

    payroll_repo = PayrollRepo(db)
    payroll = await payroll_repo.get(tenant_id, payroll_id)
    if payroll is None:
        from shared.exceptions import NotFoundError
        raise NotFoundError("حقوق یافت نشد", error_code="payroll_not_found")
    payroll.status = PayrollStatus.APPROVED

    svc = PayrollAccountingService(db)
    result = await svc.post_payroll(tenant_id, payroll_id, actor_user_id=user.user_id, profile_id=body.profile_id)
    await db.commit()
    return {"id": str(result.id), "status": result.status.value, "voucher_id": str(result.voucher_id)}


class ContractCreate(BaseModel):
    employee_id: UUID
    contract_type: str = "permanent"
    start_date: date
    end_date: date | None = None
    base_salary: Decimal = Decimal("0")


class SalaryComponentCreate(BaseModel):
    code: str
    name: str
    component_type: str = "earning"
    is_taxable: bool = True


class ContractRepo(TenantBaseRepository[EmploymentContract]):
    model = EmploymentContract


class SalaryComponentRepo(TenantBaseRepository[SalaryComponent]):
    model = SalaryComponent


@router.get("/contracts")
async def list_contracts(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await ContractRepo(db).list_by_tenant(tenant_id, limit=200)
    return [
        {
            "id": str(r.id),
            "employee_id": str(r.employee_id),
            "contract_type": r.contract_type,
            "start_date": r.start_date.isoformat(),
            "end_date": r.end_date.isoformat() if r.end_date else None,
            "base_salary": str(r.base_salary),
            "is_active": r.is_active,
        }
        for r in rows
    ]


@router.post("/contracts", status_code=status.HTTP_201_CREATED)
async def create_contract(
    body: ContractCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    entity = EmploymentContract(tenant_id=tenant_id, **body.model_dump())
    await ContractRepo(db).add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.get("/salary-components")
async def list_salary_components(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await SalaryComponentRepo(db).list_by_tenant(tenant_id, limit=200)
    return [
        {
            "id": str(r.id),
            "code": r.code,
            "name": r.name,
            "component_type": r.component_type,
            "is_taxable": r.is_taxable,
            "is_active": r.is_active,
        }
        for r in rows
    ]


@router.post("/salary-components", status_code=status.HTTP_201_CREATED)
async def create_salary_component(
    body: SalaryComponentCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    entity = SalaryComponent(tenant_id=tenant_id, **body.model_dump())
    await SalaryComponentRepo(db).add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.get("/payrolls")
async def list_payrolls(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    from app.models.payroll import Payroll
    from sqlalchemy import select

    stmt = select(Payroll).where(Payroll.tenant_id == tenant_id).order_by(Payroll.created_at.desc()).limit(200)
    rows = list((await db.execute(stmt)).scalars().all())
    return [
        {
            "id": str(r.id),
            "payroll_period_id": str(r.payroll_period_id),
            "employee_id": str(r.employee_id),
            "gross_salary": str(r.gross_salary),
            "net_salary": str(r.net_salary),
            "status": r.status.value,
            "voucher_id": str(r.voucher_id) if r.voucher_id else None,
        }
        for r in rows
    ]
