"""API настроек пользователя (валюта бюджетов и язык UI).

Per-user (ТЗ 1.2): у каждого пользователя свои настройки; строка с PK
(user_id, key). Настройки прежней эпохи (app_settings_global) копируются
в per-user при первом логине (claim) — см. services/users.py.
"""

from typing import cast

from fastapi import APIRouter

from app.dependencies import DbDep, UserIdDep
from app.models import AppSetting
from app.realtime import publish
from app.schemas import CURRENCIES, LANGUAGES, AppSettingsOut, AppSettingsUpdate
from app.services import reminders

router = APIRouter(prefix="/api/settings", tags=["settings"])

CURRENCY_KEY = "currency"
LANGUAGE_KEY = "language"
# Тихие часы напоминаний (0.89): окно «HH:MM-HH:MM», пусто — не заданы
QUIET_HOURS_KEY = "quiet_hours"
DEFAULT_CURRENCY = "UAH"
DEFAULT_LANGUAGE = ""  # '' = нет переопределения, следуем SSO locale
DEFAULT_QUIET_HOURS = ""


def _read_value(db: DbDep, user_id: str, key: str, valid: tuple[str, ...], default: str) -> str:
    row = cast(AppSetting | None, db.get(AppSetting, (user_id, key)))
    if row is not None and row.value in valid:
        return row.value
    return default


def _upsert(db: DbDep, user_id: str, key: str, value: str) -> None:
    row = cast(AppSetting | None, db.get(AppSetting, (user_id, key)))
    if row is None:
        db.add(AppSetting(user_id=user_id, key=key, value=value))
    else:
        row.value = value
    db.flush()


def _read_quiet_hours(db: DbDep, user_id: str) -> str:
    """Тихое окно наружу: только то, что разбирает планировщик.

    Значение — пользовательская настройка, и в базе может оказаться что угодно
    (правили руками). Неразбираемое отдаём как «не задано»: тем же правилом
    руководствуется и планировщик, и расхождение здесь означало бы, что интерфейс
    показывает одно, а напоминания молчат по другому.
    """
    row = cast(AppSetting | None, db.get(AppSetting, (user_id, QUIET_HOURS_KEY)))
    if row is None or reminders.parse_quiet_hours(row.value) is None:
        return DEFAULT_QUIET_HOURS
    return row.value


@router.get("", response_model=AppSettingsOut)
async def get_settings(db: DbDep, user_id: UserIdDep) -> AppSettingsOut:
    return AppSettingsOut(
        currency=_read_value(db, user_id, CURRENCY_KEY, CURRENCIES, DEFAULT_CURRENCY),
        language=_read_value(db, user_id, LANGUAGE_KEY, LANGUAGES + ("",), DEFAULT_LANGUAGE),
        quiet_hours=_read_quiet_hours(db, user_id),
    )


@router.put("", response_model=AppSettingsOut)
async def update_settings(
    schema: AppSettingsUpdate, db: DbDep, user_id: UserIdDep
) -> AppSettingsOut:
    # Частичный PUT: обновляем только переданные поля (model_fields_set)
    if schema.currency is not None:
        _upsert(db, user_id, CURRENCY_KEY, schema.currency)
    if schema.language is not None:
        _upsert(db, user_id, LANGUAGE_KEY, schema.language)
    if schema.quiet_hours is not None:
        _upsert(db, user_id, QUIET_HOURS_KEY, schema.quiet_hours)
    db.flush()
    db.commit()
    publish(user_id, "settings.changed")
    return AppSettingsOut(
        currency=_read_value(db, user_id, CURRENCY_KEY, CURRENCIES, DEFAULT_CURRENCY),
        language=_read_value(db, user_id, LANGUAGE_KEY, LANGUAGES + ("",), DEFAULT_LANGUAGE),
        quiet_hours=_read_quiet_hours(db, user_id),
    )
