from __future__ import annotations

from contextlib import asynccontextmanager

from fastapi import FastAPI
from fastapi import Query
from fastapi.middleware.cors import CORSMiddleware

from app.models import (
    Account,
    ClsNewsDocument,
    DailyInputDocument,
    DailyInputUpsertPayload,
    ReportDocument,
    ReportListItem,
)
from app.services.domain import (
    get_accounts,
    get_cls_news,
    list_reports,
    load_daily_input,
    load_report,
    normalize_daily_input,
    normalize_date,
    refresh_cls_news,
    save_daily_input,
    save_report,
    seed_demo_content,
    generate_report,
)
from app.services.storage import init_database


@asynccontextmanager
async def lifespan(_app: FastAPI):
    init_database()
    seed_demo_content()
    yield


app = FastAPI(
    title="WeChat Finance Daily",
    version="0.1.0",
    lifespan=lifespan,
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.get("/api/health")
def health() -> dict[str, str]:
    return {"status": "ok"}


@app.get("/api/accounts", response_model=list[Account])
def accounts() -> list[Account]:
    return get_accounts()


@app.get("/api/daily-inputs/{date_str}", response_model=DailyInputDocument)
def get_daily_inputs(date_str: str) -> DailyInputDocument:
    return load_daily_input(normalize_date(date_str))


@app.put("/api/daily-inputs/{date_str}", response_model=DailyInputDocument)
def put_daily_inputs(date_str: str, payload: DailyInputUpsertPayload) -> DailyInputDocument:
    document = normalize_daily_input(normalize_date(date_str), payload)
    return save_daily_input(document)


@app.post("/api/reports/{date_str}/generate", response_model=ReportDocument)
def generate_daily_report(date_str: str) -> ReportDocument:
    normalized_date = normalize_date(date_str)
    input_document = load_daily_input(normalized_date)
    report = generate_report(normalized_date, input_document)
    return save_report(report)


@app.get("/api/reports", response_model=list[ReportListItem])
def get_report_list() -> list[ReportListItem]:
    return list_reports()


@app.get("/api/opinions/{date_str}", response_model=ReportDocument)
def get_opinion_report(date_str: str) -> ReportDocument:
    normalized_date = normalize_date(date_str)
    existing = load_report(normalized_date)
    if existing is not None:
        return existing
    report = generate_report(normalized_date, load_daily_input(normalized_date))
    return save_report(report)


@app.get("/api/cls-news", response_model=ClsNewsDocument)
def get_cls_news_payload(date: str | None = Query(default=None)) -> ClsNewsDocument:
    return get_cls_news(date)


@app.post("/api/cls-news/refresh", response_model=ClsNewsDocument)
def refresh_cls_news_payload(date: str | None = Query(default=None)) -> ClsNewsDocument:
    return refresh_cls_news(date)
