"""Monthly financial report foundation — no fake data until integration exists."""

from __future__ import annotations

from datetime import datetime

from pydantic import BaseModel
from sqlalchemy import select

from app.db import FinancialReportRow, SessionLocal
from app.store import store
from app.services.snelstart.reports import get_monthly_summary


class FinancialReportOut(BaseModel):
    id: int
    clientId: str
    clientName: str | None = None
    period: str
    revenue: float | None = None
    costs: float | None = None
    netProfit: float | None = None
    previousRevenue: float | None = None
    previousCosts: float | None = None
    previousNetProfit: float | None = None
    status: str
    adviceText: str | None = None
    adviceApproved: bool = False
    generatedAt: datetime | None = None
    approvedBy: str | None = None
    approvedAt: datetime | None = None
    sentAt: datetime | None = None
    integrationRequired: bool = True


def _row_to_out(row: FinancialReportRow) -> FinancialReportOut:
    client = store.get_client(row.client_id)
    summary = get_monthly_summary(client_id=row.client_id, period=row.period)
    has_data = row.revenue is not None or row.costs is not None
    return FinancialReportOut(
        id=row.id,
        clientId=row.client_id,
        clientName=client.name if client else row.client_id,
        period=row.period,
        revenue=row.revenue,
        costs=row.costs,
        netProfit=row.net_profit,
        previousRevenue=row.previous_revenue,
        previousCosts=row.previous_costs,
        previousNetProfit=row.previous_net_profit,
        status=row.status,
        adviceText=row.advice_text,
        adviceApproved=bool(row.advice_approved),
        generatedAt=row.generated_at,
        approvedBy=row.approved_by,
        approvedAt=row.approved_at,
        sentAt=row.sent_at,
        integrationRequired=summary.integrationRequired or not has_data,
    )


def list_reports(*, client_id: str | None = None) -> list[FinancialReportOut]:
    with SessionLocal() as session:
        stmt = select(FinancialReportRow).order_by(FinancialReportRow.period.desc())
        if client_id:
            stmt = stmt.where(FinancialReportRow.client_id == client_id)
        rows = session.scalars(stmt).all()
        return [_row_to_out(r) for r in rows]


def get_report(report_id: int) -> FinancialReportOut | None:
    with SessionLocal() as session:
        row = session.get(FinancialReportRow, report_id)
        return _row_to_out(row) if row else None


def create_draft_report(*, client_id: str, period: str, actor: str) -> FinancialReportOut:
    """Create an empty draft — financial figures require SnelStart integration."""
    now = datetime.utcnow()
    with SessionLocal() as session:
        existing = session.scalar(
            select(FinancialReportRow).where(
                FinancialReportRow.client_id == client_id,
                FinancialReportRow.period == period,
            )
        )
        if existing:
            return _row_to_out(existing)

        row = FinancialReportRow(
            client_id=client_id,
            period=period,
            status="draft",
            generated_at=now,
            created_at=now,
        )
        session.add(row)
        session.commit()
        session.refresh(row)
        session.expunge(row)

    store._log(  # noqa: SLF001
        "report",
        f"Financial report draft created for {period}",
        actor,
        client_id,
    )
    return _row_to_out(row)


def approve_report_advice(*, report_id: int, actor: str) -> FinancialReportOut | None:
    with SessionLocal() as session:
        row = session.get(FinancialReportRow, report_id)
        if not row:
            return None
        row.advice_approved = True
        row.approved_by = actor
        row.approved_at = datetime.utcnow()
        row.status = "approved"
        session.commit()
        session.refresh(row)
        session.expunge(row)

    store._log(  # noqa: SLF001
        "report",
        f"Financial report advice approved for {row.period}",
        actor,
        row.client_id,
    )
    return _row_to_out(row)
