# version: v1
"""Chart-preset REST endpoints.

Wire into data_server.py:
    from chart_presets_routes import create_chart_presets_router
    app.include_router(create_chart_presets_router())

Endpoints:
    GET    /api/chart-presets         — returns dict of all named presets
    PUT    /api/chart-presets/{name}  — body is the style dict; creates or replaces
    DELETE /api/chart-presets/{name}  — removes the named preset (idempotent)
"""

import logging
from typing import Any
from urllib.parse import unquote

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel

import config_manager


log = logging.getLogger("mk.chart_presets_routes")

# Pydantic body model — accepts the full chart-style shape but is permissive
# on field presence so future shape changes don't break the API.
class ChartStyleIn(BaseModel):
    chartType: str | None = None
    background: str | None = None
    bullishColor: str | None = None
    bearishColor: str | None = None
    gridLines: bool | None = None
    marketCloseSeparator: dict | None = None
    rthSeparator: dict | None = None

    class Config:
        extra = "allow"   # forward-compat: ignore unknown keys gracefully


_RESERVED_NAMES = {"defaults", "default"}
_MAX_NAME_LEN = 60


def _validate_name(name: str) -> None:
    if not name or not name.strip():
        raise HTTPException(400, detail="Preset name cannot be empty")
    if len(name) > _MAX_NAME_LEN:
        raise HTTPException(400, detail=f"Preset name exceeds {_MAX_NAME_LEN} characters")
    if name.strip().lower() in _RESERVED_NAMES:
        raise HTTPException(400, detail=f"'{name}' is a reserved name")


def create_chart_presets_router() -> APIRouter:
    router = APIRouter(prefix="/api/chart-presets", tags=["chart-presets"])

    @router.get("")
    async def list_presets() -> dict[str, Any]:
        return config_manager.get_chart_presets()

    @router.put("/{name}")
    async def upsert_preset(name: str, body: ChartStyleIn) -> dict[str, Any]:
        decoded = unquote(name)
        _validate_name(decoded)
        try:
            config_manager.save_chart_preset(decoded, body.model_dump(exclude_none=False))
        except Exception as e:
            log.exception("save_chart_preset failed")
            raise HTTPException(500, detail=f"Save failed: {e}") from e
        return config_manager.get_chart_presets()

    @router.delete("/{name}")
    async def delete_preset(name: str) -> dict[str, Any]:
        decoded = unquote(name)
        try:
            config_manager.delete_chart_preset(decoded)
        except Exception as e:
            log.exception("delete_chart_preset failed")
            raise HTTPException(500, detail=f"Delete failed: {e}") from e
        return config_manager.get_chart_presets()

    return router
