"""System settings service — get, upsert (singleton per tenant)."""

from __future__ import annotations

import uuid
from typing import Any

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.audit import log_audit
from app.models.system_settings import SystemSettings


def _settings_to_dict(s: SystemSettings) -> dict[str, Any]:
    """Serialize SystemSettings ORM object to dict."""
    return {
        "id": str(s.id),
        "company_name": s.company_name,
        "company_legal_form": s.company_legal_form,
        "company_street": s.company_street,
        "company_city": s.company_city,
        "company_zip": s.company_zip,
        "company_country": s.company_country,
        "tax_number": s.tax_number,
        "vat_id": s.vat_id,
        "iban": s.iban,
        "bic": s.bic,
        "bank_name": s.bank_name,
        "ceo": s.ceo,
        "trade_register": s.trade_register,
        "default_currency_id": str(s.default_currency_id) if s.default_currency_id else None,
        "default_tax_id": str(s.default_tax_id) if s.default_tax_id else None,
        "invoice_prefix": s.invoice_prefix,
        "quote_prefix": s.quote_prefix,
        "payment_terms_days": s.payment_terms_days,
        "theme_primary_color": s.theme_primary_color,
        "theme_accent_color": s.theme_accent_color,
        "theme_font_family": s.theme_font_family,
        "theme_border_radius": s.theme_border_radius,
        "created_at": s.created_at.isoformat() if s.created_at else None,
        "updated_at": s.updated_at.isoformat() if s.updated_at else None,
    }


async def get_system_settings(
    db: AsyncSession,
    tenant_id: uuid.UUID,
) -> dict[str, Any] | None:
    """Get the singleton system settings for a tenant."""
    q = select(SystemSettings).where(
        SystemSettings.tenant_id == tenant_id,
        SystemSettings.deleted_at.is_(None),
    )
    result = await db.execute(q)
    settings = result.scalar_one_or_none()
    if settings is None:
        return None
    return _settings_to_dict(settings)


async def upsert_system_settings(
    db: AsyncSession,
    tenant_id: uuid.UUID,
    user_id: uuid.UUID,
    data: dict[str, Any],
) -> dict[str, Any]:
    """Upsert system settings for a tenant. Creates if not exists, updates if exists."""
    q = select(SystemSettings).where(
        SystemSettings.tenant_id == tenant_id,
        SystemSettings.deleted_at.is_(None),
    )
    result = await db.execute(q)
    settings = result.scalar_one_or_none()

    # Parse UUID fields
    default_currency_id = data.get("default_currency_id")
    if default_currency_id and isinstance(default_currency_id, str):
        try:
            default_currency_id = uuid.UUID(default_currency_id)
        except ValueError:
            default_currency_id = None

    default_tax_id = data.get("default_tax_id")
    if default_tax_id and isinstance(default_tax_id, str):
        try:
            default_tax_id = uuid.UUID(default_tax_id)
        except ValueError:
            default_tax_id = None

    if settings is None:
        # Create new settings
        settings = SystemSettings(
            tenant_id=tenant_id,
            company_name=data["company_name"],
            company_legal_form=data.get("company_legal_form"),
            company_street=data["company_street"],
            company_city=data["company_city"],
            company_zip=data["company_zip"],
            company_country=data["company_country"],
            tax_number=data.get("tax_number"),
            vat_id=data.get("vat_id"),
            iban=data.get("iban"),
            bic=data.get("bic"),
            bank_name=data.get("bank_name"),
            ceo=data.get("ceo"),
            trade_register=data.get("trade_register"),
            default_currency_id=default_currency_id,
            default_tax_id=default_tax_id,
            invoice_prefix=data.get("invoice_prefix", "RE-"),
            quote_prefix=data.get("quote_prefix", "AN-"),
            payment_terms_days=data.get("payment_terms_days", 14),
            theme_primary_color=data.get("theme_primary_color", "#2563eb"),
            theme_accent_color=data.get("theme_accent_color", "#d946ef"),
            theme_font_family=data.get("theme_font_family", "Inter"),
            theme_border_radius=data.get("theme_border_radius", "0.5rem"),
        )
        db.add(settings)
        await db.flush()
        await db.refresh(settings)
        await log_audit(
            db, tenant_id, user_id, "create", "system_settings", settings.id,
            changes={"company_name": settings.company_name},
        )
    else:
        # Update existing settings
        changes: dict[str, Any] = {}
        all_fields = (
            "company_name", "company_legal_form", "company_street", "company_city",
            "company_zip", "company_country", "tax_number", "vat_id", "iban",
            "bic", "bank_name", "ceo", "trade_register",
            "invoice_prefix", "quote_prefix", "payment_terms_days",
            "theme_primary_color", "theme_accent_color", "theme_font_family", "theme_border_radius",
        )
        for field in all_fields:
            if field in data and data[field] is not None:
                old_val = getattr(settings, field)
                changes[field] = {"old": old_val, "new": data[field]}
                setattr(settings, field, data[field])

        if default_currency_id is not None or data.get("default_currency_id") is None and "default_currency_id" in data:
            changes["default_currency_id"] = {"old": str(settings.default_currency_id) if settings.default_currency_id else None, "new": str(default_currency_id) if default_currency_id else None}
            settings.default_currency_id = default_currency_id

        if default_tax_id is not None or data.get("default_tax_id") is None and "default_tax_id" in data:
            changes["default_tax_id"] = {"old": str(settings.default_tax_id) if settings.default_tax_id else None, "new": str(default_tax_id) if default_tax_id else None}
            settings.default_tax_id = default_tax_id

        await db.flush()
        await db.refresh(settings)
        await log_audit(db, tenant_id, user_id, "update", "system_settings", settings.id, changes=changes)

    return _settings_to_dict(settings)
