"""Gear registry endpoints (/api/gear)."""
from __future__ import annotations

import json
import uuid
from pathlib import Path

from fastapi import APIRouter, Cookie, HTTPException, Request
from fastapi.responses import JSONResponse

from bincio.serve import deps

router = APIRouter()

_GEAR_TYPES = {"bike", "shoes", "skis", "other"}


def _gear_path(user_dir: Path) -> Path:
    return user_dir / "gear.json"


def _load(user_dir: Path) -> list[dict]:
    p = _gear_path(user_dir)
    if not p.exists():
        return []
    try:
        data = json.loads(p.read_text(encoding="utf-8"))
        return data.get("items", [])
    except (OSError, json.JSONDecodeError):
        return []


def _save(user_dir: Path, items: list[dict]) -> None:
    _gear_path(user_dir).write_text(
        json.dumps({"items": items}, indent=2, ensure_ascii=False),
        encoding="utf-8",
    )


@router.get("/api/gear")
async def gear_list(bincio_session: str | None = Cookie(default=None)) -> JSONResponse:
    user = deps._require_user(bincio_session)
    items = _load(deps._get_data_dir() / user.handle)
    return JSONResponse({"items": items})


@router.post("/api/gear")
async def gear_add(
    request: Request,
    bincio_session: str | None = Cookie(default=None),
) -> JSONResponse:
    user = deps._require_user(bincio_session)
    body = await request.json()
    name = str(body.get("name", "")).strip()
    if not name:
        raise HTTPException(400, "name is required")
    gear_type = str(body.get("type", "other")).strip()
    if gear_type not in _GEAR_TYPES:
        raise HTTPException(400, f"type must be one of: {', '.join(sorted(_GEAR_TYPES))}")
    strava_id = str(body.get("strava_id", "")).strip() or None

    user_dir = deps._get_data_dir() / user.handle
    items = _load(user_dir)

    # Deduplicate by strava_id if provided
    if strava_id and any(i.get("strava_id") == strava_id for i in items):
        existing = next(i for i in items if i.get("strava_id") == strava_id)
        return JSONResponse({"ok": True, "item": existing, "created": False})

    item: dict = {
        "id": str(uuid.uuid4()),
        "name": name,
        "type": gear_type,
        "retired": False,
    }
    if strava_id:
        item["strava_id"] = strava_id

    items.append(item)
    _save(user_dir, items)
    return JSONResponse({"ok": True, "item": item, "created": True}, status_code=201)


@router.patch("/api/gear/{item_id}")
async def gear_update(
    item_id: str,
    request: Request,
    bincio_session: str | None = Cookie(default=None),
) -> JSONResponse:
    user = deps._require_user(bincio_session)
    user_dir = deps._get_data_dir() / user.handle
    items = _load(user_dir)

    idx = next((i for i, g in enumerate(items) if g["id"] == item_id), None)
    if idx is None:
        raise HTTPException(404, "Gear item not found")

    body = await request.json()
    item = dict(items[idx])

    if "name" in body:
        name = str(body["name"]).strip()
        if not name:
            raise HTTPException(400, "name cannot be empty")
        item["name"] = name
    if "type" in body:
        gear_type = str(body["type"]).strip()
        if gear_type not in _GEAR_TYPES:
            raise HTTPException(400, f"type must be one of: {', '.join(sorted(_GEAR_TYPES))}")
        item["type"] = gear_type
    if "retired" in body:
        item["retired"] = bool(body["retired"])

    items[idx] = item
    _save(user_dir, items)
    return JSONResponse({"ok": True, "item": item})


@router.delete("/api/gear/{item_id}")
async def gear_delete(
    item_id: str,
    bincio_session: str | None = Cookie(default=None),
) -> JSONResponse:
    user = deps._require_user(bincio_session)
    user_dir = deps._get_data_dir() / user.handle
    items = _load(user_dir)

    before = len(items)
    items = [g for g in items if g["id"] != item_id]
    if len(items) == before:
        raise HTTPException(404, "Gear item not found")

    _save(user_dir, items)
    return JSONResponse({"ok": True})
