"""Home Assistant source storage using SQLite."""

import uuid
from datetime import datetime, timezone
from typing import List, Optional

from ledgrab.storage.base_sqlite_store import BaseSqliteStore
from ledgrab.storage.database import Database
from ledgrab.storage.home_assistant_source import HomeAssistantSource
from ledgrab.utils import get_logger, secret_box

logger = get_logger(__name__)


class HomeAssistantStore(BaseSqliteStore[HomeAssistantSource]):
    """Persistent storage for Home Assistant sources."""

    _table_name = "home_assistant_sources"
    _entity_name = "Home Assistant source"

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

    def _migrate_plaintext_tokens(self) -> None:
        """Encrypt any stored HA tokens that are still in plaintext at rest.

        Per project Data Migration Policy: detect old format, transform
        in place, log loudly. We inspect the raw DB rows (not the in-memory
        cache, which already holds decrypted plaintext) and re-save items
        whose disk row lacks the encryption envelope.
        """
        migrated = 0
        try:
            rows = self._db.load_all(self._table_name)
        except Exception as exc:
            logger.error("Could not inspect rows for HA token migration: %s", exc)
            return
        for row in rows:
            sid = row.get("id")
            raw_token = row.get("token", "") or ""
            if not sid or not raw_token:
                continue
            if secret_box.is_encrypted(raw_token):
                continue
            source = self._items.get(sid)
            if source is None:
                continue
            try:
                # to_dict() encrypts the token; _save_item writes the row.
                self._save_item(sid, source)
                migrated += 1
            except Exception as exc:
                logger.error("Failed to migrate HA token for %s: %s", sid, exc)
        if migrated:
            logger.warning(
                "MIGRATION: encrypted %d plaintext Home Assistant token(s) at rest. "
                "Existing DB rows have been rewritten in encrypted form.",
                migrated,
            )

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

    def create_source(
        self,
        name: str,
        host: str,
        token: str,
        use_ssl: bool = False,
        entity_filters: Optional[List[str]] = None,
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
    ) -> HomeAssistantSource:
        if not host:
            raise ValueError("host is required")
        if not token:
            raise ValueError("token is required")

        self._check_name_unique(name)

        sid = f"has_{uuid.uuid4().hex[:8]}"
        now = datetime.now(timezone.utc)

        source = HomeAssistantSource(
            id=sid,
            name=name,
            created_at=now,
            updated_at=now,
            host=host,
            token=token,
            use_ssl=use_ssl,
            entity_filters=entity_filters or [],
            description=description,
            tags=tags or [],
        )

        self._items[sid] = source
        self._save_item(sid, source)
        logger.info(f"Created Home Assistant source: {name} ({sid})")
        return source

    def update_source(
        self,
        source_id: str,
        name: Optional[str] = None,
        host: Optional[str] = None,
        token: Optional[str] = None,
        use_ssl: Optional[bool] = None,
        entity_filters: Optional[List[str]] = None,
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
    ) -> HomeAssistantSource:
        existing = self.get(source_id)

        if name is not None and name != existing.name:
            self._check_name_unique(name)

        updated = HomeAssistantSource(
            id=existing.id,
            name=name if name is not None else existing.name,
            created_at=existing.created_at,
            updated_at=datetime.now(timezone.utc),
            host=host if host is not None else existing.host,
            token=token if token is not None else existing.token,
            use_ssl=use_ssl if use_ssl is not None else existing.use_ssl,
            entity_filters=(
                entity_filters if entity_filters is not None else existing.entity_filters
            ),
            description=description if description is not None else existing.description,
            tags=tags if tags is not None else existing.tags,
        )

        self._items[source_id] = updated
        self._save_item(source_id, updated)
        logger.info(f"Updated Home Assistant source: {updated.name} ({source_id})")
        return updated
