"""Phase 5.8 — Fixed Assets 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.fixed_assets import Asset, AssetCategory, AssetDisposal, AssetRevaluation, AssetTransfer
from app.models.types import AssetStatus, DepreciationMethod
from app.repositories.base import TenantBaseRepository
from app.services.asset_service import AssetAccountingService, DepreciationEngine
from shared.security import CurrentUser

router = APIRouter()


class AssetCategoryCreate(BaseModel):
    code: str
    name: str
    default_useful_life_months: int = 60
    default_depreciation_method: DepreciationMethod = DepreciationMethod.STRAIGHT_LINE


class AssetCreate(BaseModel):
    code: str
    name: str
    category_id: UUID | None = None
    acquisition_cost: Decimal = Decimal("0")
    residual_value: Decimal = Decimal("0")
    useful_life_months: int = 60
    depreciation_method: DepreciationMethod = DepreciationMethod.STRAIGHT_LINE


class DepreciateRequest(BaseModel):
    expense_account_id: UUID
    accumulated_account_id: UUID


class AssetCategoryRepo(TenantBaseRepository[AssetCategory]):
    model = AssetCategory


class AssetRepo(TenantBaseRepository[Asset]):
    model = Asset


@router.post("/categories", status_code=status.HTTP_201_CREATED)
async def create_category(
    body: AssetCategoryCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    repo = AssetCategoryRepo(db)
    entity = AssetCategory(tenant_id=tenant_id, **body.model_dump())
    await repo.add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.get("/categories")
async def list_categories(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    cats = await AssetCategoryRepo(db).list_by_tenant(tenant_id, limit=100)
    return [
        {
            "id": str(c.id),
            "code": c.code,
            "name": c.name,
            "default_useful_life_months": c.default_useful_life_months,
        }
        for c in cats
    ]


@router.post("/assets", status_code=status.HTTP_201_CREATED)
async def create_asset(
    body: AssetCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    repo = AssetRepo(db)
    entity = Asset(tenant_id=tenant_id, status=AssetStatus.DRAFT, **body.model_dump())
    await repo.add(entity)
    await db.commit()
    return {"id": str(entity.id), "code": entity.code}


@router.get("/assets", response_model=list[dict])
async def list_assets(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    repo = AssetRepo(db)
    assets = await repo.list_by_tenant(tenant_id, limit=100)
    return [{"id": str(a.id), "code": a.code, "name": a.name, "status": a.status.value} for a in assets]


@router.post("/assets/{asset_id}/activate")
async def activate_asset(
    asset_id: UUID,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(get_current_user),
):
    svc = AssetAccountingService(db)
    asset = await svc.activate_asset(tenant_id, asset_id, user.user_id)
    await db.commit()
    return {"id": str(asset.id), "status": asset.status.value}


@router.post("/assets/{asset_id}/depreciate")
async def depreciate_asset(
    asset_id: UUID,
    body: DepreciateRequest,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(get_current_user),
):
    svc = AssetAccountingService(db)
    dep = await svc.depreciate_asset(
        tenant_id, asset_id,
        expense_account_id=body.expense_account_id,
        accumulated_account_id=body.accumulated_account_id,
        actor_user_id=user.user_id,
    )
    await db.commit()
    return {"id": str(dep.id), "amount": str(dep.amount), "voucher_id": str(dep.voucher_id)}


@router.get("/assets/{asset_id}/depreciation-schedule")
async def get_depreciation_schedule(
    asset_id: UUID,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    repo = AssetRepo(db)
    asset = await repo.get(tenant_id, asset_id)
    if asset is None:
        return {"schedule": []}
    engine = DepreciationEngine()
    return {"schedule": engine.generate_schedule(asset)}


class AssetTransferCreate(BaseModel):
    asset_id: UUID
    transfer_date: date
    from_location: str | None = None
    to_location: str | None = None


class AssetDisposalCreate(BaseModel):
    asset_id: UUID
    disposal_date: date
    disposal_type: str = "sale"
    sale_amount: Decimal | None = None


class AssetRevaluationCreate(BaseModel):
    asset_id: UUID
    revaluation_date: date
    old_book_value: Decimal
    new_book_value: Decimal


class AssetTransferRepo(TenantBaseRepository[AssetTransfer]):
    model = AssetTransfer


class AssetDisposalRepo(TenantBaseRepository[AssetDisposal]):
    model = AssetDisposal


class AssetRevaluationRepo(TenantBaseRepository[AssetRevaluation]):
    model = AssetRevaluation


@router.get("/transfers")
async def list_transfers(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await AssetTransferRepo(db).list_by_tenant(tenant_id, limit=200)
    return [
        {
            "id": str(r.id),
            "asset_id": str(r.asset_id),
            "transfer_date": r.transfer_date.isoformat(),
            "from_location": r.from_location,
            "to_location": r.to_location,
        }
        for r in rows
    ]


@router.post("/transfers", status_code=status.HTTP_201_CREATED)
async def create_transfer(
    body: AssetTransferCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    entity = AssetTransfer(tenant_id=tenant_id, **body.model_dump())
    await AssetTransferRepo(db).add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.get("/disposals")
async def list_disposals(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await AssetDisposalRepo(db).list_by_tenant(tenant_id, limit=200)
    return [
        {
            "id": str(r.id),
            "asset_id": str(r.asset_id),
            "disposal_date": r.disposal_date.isoformat(),
            "disposal_type": r.disposal_type,
            "sale_amount": str(r.sale_amount) if r.sale_amount is not None else None,
            "gain_loss": str(r.gain_loss) if r.gain_loss is not None else None,
        }
        for r in rows
    ]


@router.post("/disposals", status_code=status.HTTP_201_CREATED)
async def create_disposal(
    body: AssetDisposalCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    entity = AssetDisposal(tenant_id=tenant_id, **body.model_dump())
    await AssetDisposalRepo(db).add(entity)
    await db.commit()
    return {"id": str(entity.id)}


@router.get("/revaluations")
async def list_revaluations(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    rows = await AssetRevaluationRepo(db).list_by_tenant(tenant_id, limit=200)
    return [
        {
            "id": str(r.id),
            "asset_id": str(r.asset_id),
            "revaluation_date": r.revaluation_date.isoformat(),
            "old_book_value": str(r.old_book_value),
            "new_book_value": str(r.new_book_value),
            "difference": str(r.difference),
        }
        for r in rows
    ]


@router.post("/revaluations", status_code=status.HTTP_201_CREATED)
async def create_revaluation(
    body: AssetRevaluationCreate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    diff = body.new_book_value - body.old_book_value
    entity = AssetRevaluation(
        tenant_id=tenant_id,
        asset_id=body.asset_id,
        revaluation_date=body.revaluation_date,
        old_book_value=body.old_book_value,
        new_book_value=body.new_book_value,
        difference=diff,
    )
    await AssetRevaluationRepo(db).add(entity)
    await db.commit()
    return {"id": str(entity.id), "difference": str(diff)}
