from __future__ import annotations

from pathlib import Path
from typing import Any

from fastapi import FastAPI, File, Form, UploadFile
from fastapi.responses import HTMLResponse, JSONResponse, Response

from server.app_service import (
    AppInputError,
    UploadedFile,
    calculate_payload,
    prepare_payload,
    sample_data_archive,
    template_workbook,
)

app = FastAPI()
INDEX_HTML = Path(__file__).resolve().parent / "index.html"


async def _upload_file(file: UploadFile | None) -> UploadedFile | None:
    if file is None or not file.filename:
        return None
    return UploadedFile(name=file.filename.replace("\\", "/").split("/")[-1], data=await file.read())


async def _upload_files(files: list[UploadFile] | None) -> list[UploadedFile]:
    result: list[UploadedFile] = []
    for file in files or []:
        item = await _upload_file(file)
        if item is not None:
            result.append(item)
    return result


def _json(payload: dict[str, Any], status_code: int = 200) -> JSONResponse:
    return JSONResponse(content=payload, status_code=status_code, headers={"cache-control": "no-store"})


def _error(exc: Exception) -> JSONResponse:
    if isinstance(exc, AppInputError):
        return _json({"ok": False, "error": str(exc)}, status_code=400)
    return _json({"ok": False, "error": f"服务端计算失败：{exc}"}, status_code=500)


@app.get("/", response_class=HTMLResponse)
@app.get("/index.html", response_class=HTMLResponse)
async def index() -> HTMLResponse:
    return HTMLResponse(INDEX_HTML.read_text(encoding="utf-8"))


@app.post("/api/prepare")
async def prepare(
    use_sample: str = Form("0"),
    files: list[UploadFile] | None = File(None),
    business_config: UploadFile | None = File(None),
) -> JSONResponse:
    try:
        payload = prepare_payload(
            use_sample=use_sample == "1",
            uploaded_files=await _upload_files(files),
            config_file=await _upload_file(business_config),
        )
        return _json(payload, status_code=200 if payload.get("ok", True) else 400)
    except Exception as exc:
        return _error(exc)


@app.post("/api/calculate")
async def calculate(
    use_sample: str = Form("0"),
    settings: str = Form("{}"),
    action: str = Form("preview"),
    files: list[UploadFile] | None = File(None),
    business_config: UploadFile | None = File(None),
) -> JSONResponse:
    import json

    try:
        try:
            parsed_settings = json.loads(settings) if settings else {}
        except json.JSONDecodeError:
            raise AppInputError("页面设置解析失败，请刷新页面后重试。")
        payload = calculate_payload(
            use_sample=use_sample == "1",
            uploaded_files=await _upload_files(files),
            config_file=await _upload_file(business_config),
            settings=parsed_settings,
            action=action,
        )
        return _json(payload, status_code=200 if payload.get("ok", True) else 400)
    except Exception as exc:
        return _error(exc)


@app.get("/api/template")
async def template() -> Response:
    try:
        return Response(
            content=template_workbook(),
            media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            headers={
                "cache-control": "no-store",
                "content-disposition": "attachment; filename*=UTF-8''%E5%8F%A3%E5%BE%84%E9%85%8D%E7%BD%AE%E6%A8%A1%E6%9D%BF.xlsx",
            },
        )
    except Exception as exc:
        return _error(exc)


@app.get("/api/sample-data")
async def sample_data() -> Response:
    try:
        return Response(
            content=sample_data_archive(),
            media_type="application/zip",
            headers={
                "cache-control": "no-store",
                "content-disposition": "attachment; filename*=UTF-8''%E6%A0%B7%E4%BE%8B%E6%95%B0%E6%8D%AE.zip",
            },
        )
    except Exception as exc:
        return _error(exc)
