"""Setup progress + document number sequences API."""
from __future__ import annotations

from uuid import UUID

from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel, Field
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.repositories.foundation import (
    AccountRepository,
    ChartOfAccountsRepository,
    CurrencyRepository,
    FiscalPeriodRepository,
    FiscalYearRepository,
)
from app.repositories.posting import VoucherRepository
from app.schemas.foundation import SetupStatusRead
from app.services.document_number_service import DocumentNumberService
from shared.security import CurrentUser

router = APIRouter()


class AllocateRequest(BaseModel):
    document_type: str = Field(min_length=1, max_length=50)


class SequencePreview(BaseModel):
    document_type: str
    prefix: str
    next_number: int
    padding: int
    preview: str


@router.get("/status", response_model=SetupStatusRead)
async def setup_status(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    charts = await ChartOfAccountsRepository(db).list_by_tenant(tenant_id, limit=1)
    accounts = await AccountRepository(db).list_by_tenant(tenant_id, limit=1)
    currencies = await CurrencyRepository(db).list_by_tenant(tenant_id, limit=100)
    years = await FiscalYearRepository(db).list_by_tenant(tenant_id, limit=1)
    periods = await FiscalPeriodRepository(db).list_by_tenant(tenant_id, limit=1)

    has_cash = False
    has_customer = False
    try:
        from app.api.v1.treasury import CashBoxRepo
        from app.api.v1.receivable_payable import CustomerRepo

        has_cash = bool(await CashBoxRepo(db).list_by_tenant(tenant_id, limit=1))
        has_customer = bool(await CustomerRepo(db).list_by_tenant(tenant_id, limit=1))
    except Exception:
        pass

    has_voucher = bool(await VoucherRepository(db).list_by_tenant(tenant_id, limit=1))

    flags = {
        "has_chart": bool(charts),
        "has_accounts": bool(accounts),
        "has_currency": bool(currencies),
        "has_base_currency": any(c.is_base for c in currencies),
        "has_fiscal_year": bool(years),
        "has_fiscal_period": bool(periods),
        "has_cash_box": has_cash,
        "has_customer": has_customer,
        "has_voucher": has_voucher,
    }
    completed = sum(1 for v in flags.values() if v)
    total = len(flags)
    return SetupStatusRead(
        **flags,
        completed_steps=completed,
        total_steps=total,
        percent=round(100 * completed / total) if total else 0,
    )


@router.get("/sequences/next", response_model=SequencePreview)
async def peek_next_number(
    document_type: str = Query(min_length=1, max_length=50),
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    """Preview next number without consuming it (for form autofill)."""
    svc = DocumentNumberService(db)
    data = await svc.peek(tenant_id, document_type)
    await db.commit()
    return SequencePreview(**data)


@router.post("/sequences/allocate")
async def allocate_number(
    body: AllocateRequest,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    """Consume and return the next number for a document type."""
    svc = DocumentNumberService(db)
    number = await svc.allocate(tenant_id, body.document_type)
    await db.commit()
    return {"document_type": body.document_type, "number": number}


class PostingPolicyUpdate(BaseModel):
    auto_post: dict[str, bool] | None = None
    require_balanced: bool | None = None
    require_source_reference: bool | None = None
    lock_after_post: bool | None = None
    sequential_numbers: bool | None = None
    idempotent_source: bool | None = None
    posting_mode: str | None = None


@router.get("/posting-policy")
async def get_posting_policy(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    from app.services.posting_policy_service import PostingPolicyService

    return await PostingPolicyService(db).get_policy(tenant_id)


@router.put("/posting-policy")
async def update_posting_policy(
    body: PostingPolicyUpdate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    from app.services.posting_policy_service import PostingPolicyService

    policy = await PostingPolicyService(db).update_policy(
        tenant_id, body.model_dump(exclude_none=True)
    )
    await db.commit()
    return policy


class CompanyProfileUpdate(BaseModel):
    legal_name: str | None = None
    trade_name: str | None = None
    national_id: str | None = None
    economic_code: str | None = None
    registration_number: str | None = None
    postal_code: str | None = None
    province: str | None = None
    city: str | None = None
    address: str | None = None
    phone: str | None = None
    mobile: str | None = None
    email: str | None = None
    website: str | None = None
    ceo_name: str | None = None
    accountant_name: str | None = None


@router.get("/company-profile")
async def get_company_profile(
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    from app.services.company_profile_service import CompanyProfileService

    return await CompanyProfileService(db).get_profile(tenant_id)


@router.put("/company-profile")
async def update_company_profile(
    body: CompanyProfileUpdate,
    tenant_id: UUID = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
    _user: CurrentUser = Depends(get_current_user),
):
    from app.services.company_profile_service import CompanyProfileService

    profile = await CompanyProfileService(db).update_profile(
        tenant_id, body.model_dump(exclude_none=False)
    )
    await db.commit()
    return profile
