from __future__ import annotations

from sqlite3 import Connection

from fastapi import APIRouter, Depends, HTTPException, Query

from jarvis_finance.api.dependencies import get_db
from jarvis_finance.api.schemas.overview import PortfolioSummary
from jarvis_finance.api.schemas.portfolio_advisor import PortfolioAdvisorSnapshot
from jarvis_finance.api.schemas.reconciliation import ReconciliationSnapshotResponse
from jarvis_finance.api.schemas.portfolio_policy import ActivePortfolioPolicyResponse, PolicyConfirmRequest, PolicyConfirmResponse, PolicyEvaluationResponse, PolicyHistoryItem, PolicyPreviewRequest, PolicyPreviewResponse, PortfolioPolicyResponse
from jarvis_finance.api.schemas.portfolio_performance import PortfolioPerformanceResponse
from jarvis_finance.api.schemas.portfolio_data import (
    DataSourcesResponse,
    IngestionConfirmRequest,
    IngestionConfirmResponse,
    IngestionHistoryResponse,
    IngestionPreviewRequest,
    IngestionPreviewResponse,
    ReconciliationResponse,
)
from jarvis_finance.services.portfolio_policy import active_policy, confirm_policy, evaluate_policy, policy_detail, policy_history, preview_policy
from jarvis_finance.services.portfolio_performance import build_portfolio_performance
from jarvis_finance.services.portfolio_analytics import build_portfolio_analytics
from jarvis_finance.services.portfolio_data import (
    build_portfolio_reconciliation,
    confirm_ingestion,
    ingestion_history,
    list_data_sources,
    preview_ingestion,
)
from jarvis_finance.services.portfolio_service import get_overview
from jarvis_finance.services.portfolio_advisor import get_portfolio_advisor_snapshot
from jarvis_finance.services.reconciliation_snapshot import build_reconciliation_snapshot
from jarvis_finance.services.finance_command_center import build_finance_command_center

router = APIRouter(tags=["overview"])


@router.get("/overview/finance-command-center")
def finance_command_center(month: str | None = None, conn: Connection = Depends(get_db)) -> dict:
    try:
        return build_finance_command_center(conn, month=month)
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get("/overview", response_model=PortfolioSummary)
def overview(conn: Connection = Depends(get_db)) -> PortfolioSummary:
    return get_overview(conn)


@router.get("/portfolio/reconciliation-snapshot", response_model=ReconciliationSnapshotResponse)
def reconciliation_snapshot(conn: Connection = Depends(get_db)) -> ReconciliationSnapshotResponse:
    """Read-only local quality view; it never imports, corrects, or confirms data."""
    return ReconciliationSnapshotResponse.model_validate(build_reconciliation_snapshot(conn))


@router.get("/portfolio/data-sources", response_model=DataSourcesResponse)
def portfolio_data_sources(conn: Connection = Depends(get_db)) -> dict:
    """Read source availability and redacted ingestion status without fetching providers."""
    return list_data_sources(conn)


@router.post("/portfolio/ingestion/preview", response_model=IngestionPreviewResponse)
def portfolio_ingestion_preview(request: IngestionPreviewRequest, conn: Connection = Depends(get_db)) -> dict:
    """Pure preview over already-normalized local records; no source is fetched or mutated."""
    try:
        return preview_ingestion(conn, request.model_dump())
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.post(
    "/portfolio/ingestion/confirm",
    response_model=IngestionConfirmResponse,
    responses={409: {"description": "Abgelaufene oder veränderte Preview"}},
)
def portfolio_ingestion_confirm(request: IngestionConfirmRequest, conn: Connection = Depends(get_db)) -> dict:
    """The only portfolio-ingestion write path: atomic, idempotent and audited."""
    try:
        return confirm_ingestion(conn, request.model_dump())
    except ValueError as exc:
        message = str(exc)
        status = 409 if any(word in message.lower() for word in ("abgelaufen", "veraltet", "verändert", "ausgangsrevision", "wiederverwendet")) else 400
        raise HTTPException(status_code=status, detail=message) from exc


@router.get("/portfolio/ingestion/history", response_model=IngestionHistoryResponse)
def portfolio_ingestion_history(
    limit: int = Query(default=50, ge=1, le=100),
    offset: int = Query(default=0, ge=0),
    conn: Connection = Depends(get_db),
) -> dict:
    return ingestion_history(conn, limit=limit, offset=offset)


@router.get("/portfolio/reconciliation", response_model=ReconciliationResponse)
def portfolio_reconciliation(
    as_of: str,
    data_cutoff: str | None = None,
    account_id: str | None = None,
    base_currency: str = "CHF",
    absolute_tolerance: str = "0.01",
    relative_tolerance: str = "0.001",
    limit: int = Query(default=200, ge=1, le=500),
    offset: int = Query(default=0, ge=0),
    conn: Connection = Depends(get_db),
) -> dict:
    """Read-only reproducible quantity, valuation, account-total and coverage reconciliation."""
    try:
        return build_portfolio_reconciliation(
            conn, as_of=as_of, data_cutoff=data_cutoff, account_id=account_id,
            base_currency=base_currency, absolute_tolerance=absolute_tolerance,
            relative_tolerance=relative_tolerance, limit=limit, offset=offset,
        )
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get(
    "/portfolio/performance",
    response_model=PortfolioPerformanceResponse,
    responses={400: {"description": "Ungültiger Performance-Zeitraum oder Parameter"}},
)
def portfolio_performance(
    from_date: str = Query(alias="from"),
    to_date: str = Query(alias="to"),
    method: str = Query(default="both"),
    account_id: str | None = None,
    base_currency: str = Query(default="CHF"),
    data_cutoff: str | None = None,
    conn: Connection = Depends(get_db),
) -> dict:
    """Pure read-only calculation from stored activities and versioned snapshots."""

    try:
        return build_portfolio_performance(
            conn,
            from_date=from_date,
            to_date=to_date,
            method=method,
            account_id=account_id,
            base_currency=base_currency,
            data_cutoff=data_cutoff,
        )
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get("/portfolio/analytics")
def portfolio_analytics(
    period: str = Query(default="1y", pattern="^(1m|3m|6m|1y|2y)$"),
    conn: Connection = Depends(get_db),
) -> dict:
    """Read-only market/FX, benchmark and risk projection from stored confirmed snapshots."""
    return build_portfolio_analytics(conn, period=period)


@router.get("/portfolio/policy", response_model=ActivePortfolioPolicyResponse)
def portfolio_policy(conn: Connection = Depends(get_db)) -> dict:
    return active_policy(conn)


@router.get("/portfolio/policy/history", response_model=list[PolicyHistoryItem])
def portfolio_policy_history(conn: Connection = Depends(get_db)) -> list[dict]:
    return policy_history(conn)


@router.post("/portfolio/policy/preview", response_model=PolicyPreviewResponse)
def portfolio_policy_preview(request: PolicyPreviewRequest, conn: Connection = Depends(get_db)) -> dict:
    return preview_policy(conn, request.model_dump())


@router.post("/portfolio/policy/confirm", response_model=PolicyConfirmResponse)
def portfolio_policy_confirm(request: PolicyConfirmRequest, conn: Connection = Depends(get_db)) -> dict:
    try:
        return confirm_policy(conn, request.model_dump())
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get("/portfolio/policy/evaluation", response_model=PolicyEvaluationResponse)
def portfolio_policy_evaluation(conn: Connection = Depends(get_db)) -> dict:
    return evaluate_policy(conn)


@router.get(
    "/portfolio/policy/{policy_id}",
    response_model=PortfolioPolicyResponse,
    responses={404: {"description": "Policy-Version nicht gefunden"}},
)
def portfolio_policy_detail(policy_id: str, conn: Connection = Depends(get_db)) -> dict:
    policy = policy_detail(conn, policy_id)
    if policy is None:
        raise HTTPException(status_code=404, detail="Policy-Version nicht gefunden")
    return policy


@router.get("/portfolio/advisor", response_model=PortfolioAdvisorSnapshot)
def portfolio_advisor(conn: Connection = Depends(get_db)) -> PortfolioAdvisorSnapshot:
    return get_portfolio_advisor_snapshot(conn)
