"""Value source storage using SQLite.

Per-type create / update logic lives in
``ledgrab.storage.value_source_factories`` so this module stays focused
on the BaseSqliteStore protocol (load, save, name uniqueness, common
fields). See audit finding C7 for context on the previous if/elif
ladder this layout replaces.
"""

import uuid
from datetime import datetime, timezone

from ledgrab.storage.base_sqlite_store import BaseSqliteStore
from ledgrab.storage.database import Database
from ledgrab.storage.value_source import ValueSource
from ledgrab.storage.value_source_factories import (
    apply_update as _apply_value_source_update,
    build_source as _build_value_source,
)
from ledgrab.utils import get_logger

logger = get_logger(__name__)


class ValueSourceStore(BaseSqliteStore[ValueSource]):
    """Persistent storage for value sources."""

    _table_name = "value_sources"
    _entity_name = "Value source"

    def __init__(self, db: Database):
        super().__init__(db, ValueSource.from_dict)

    # Backward-compatible aliases
    get_all_sources = BaseSqliteStore.get_all
    get_source = BaseSqliteStore.get
    delete_source = BaseSqliteStore.delete

    # ── CRUD ─────────────────────────────────────────────────────────

    def create_source(self, name: str, source_type: str, **kwargs) -> ValueSource:
        """Create a new value source.

        Per-type construction (defaults, validation, sub-mode dispatch)
        lives in ``value_source_factories.CREATE_BUILDERS`` so the store
        only owns name-uniqueness, id minting, and persistence.

        Validation order is: source_type membership → type-specific field
        validation → name uniqueness. This matches the pre-refactor
        precedence so an invalid ``source_type`` + a duplicate ``name``
        still surface as ``"Invalid source type: …"`` instead of the
        name-collision error.
        """
        sid = f"vs_{uuid.uuid4().hex[:8]}"
        now = datetime.now(timezone.utc)

        source = _build_value_source(
            source_type=source_type,
            sid=sid,
            name=name,
            now=now,
            description=kwargs.pop("description", None),
            tags=kwargs.pop("tags", None),
            icon=kwargs.pop("icon", None),
            icon_color=kwargs.pop("icon_color", None),
            **kwargs,
        )

        # Name-uniqueness happens last so we never burn a uuid on a source
        # we end up rejecting AND so the user-facing error precedence
        # (type errors before name errors) matches the old code's order.
        self._check_name_unique(name)

        self._items[sid] = source
        self._save_item(sid, source)

        logger.info(f"Created value source: {name} ({sid}, type={source_type})")
        return source

    def update_source(self, source_id: str, **kwargs) -> ValueSource:
        """Update an existing value source.

        Common fields (name, description, tags, icon, icon_color) are
        applied here; per-type field updates are delegated to
        ``value_source_factories.apply_update`` (which dispatches on
        ``source.source_type``).
        """
        source = self.get(source_id)

        name = kwargs.pop("name", None)
        if name is not None:
            self._check_name_unique(name, exclude_id=source_id)
            source.name = name

        description = kwargs.pop("description", None)
        if description is not None:
            source.description = description

        tags = kwargs.pop("tags", None)
        if tags is not None:
            source.tags = tags

        icon = kwargs.pop("icon", None)
        if icon is not None:
            source.icon = icon

        icon_color = kwargs.pop("icon_color", None)
        if icon_color is not None:
            source.icon_color = icon_color

        # Per-type field updates (and per-type validation) live in the
        # factories module so adding a new value-source kind requires only
        # one new builder + one new applier and no store edits.
        _apply_value_source_update(source, **kwargs)

        source.updated_at = datetime.now(timezone.utc)
        self._save_item(source_id, source)

        logger.info(f"Updated value source: {source_id}")
        return source
