"""Persistence for Copy-on-Write pool and dataset state."""

from __future__ import annotations

import os
import stat
from pathlib import Path

import yaml

from gaol.config import get_data_dir
from gaol.cow.models import (
    DatasetState,
    DatasetsStore,
    PoolState,
    PoolsStore,
)


def _get_cow_dir() -> Path:
    """Get the CoW data directory."""
    return get_data_dir() / "cow"


class CoWStore:
    """Persistent storage for CoW pool and dataset state.

    Stores pool and dataset metadata in YAML files with restrictive permissions.
    """

    def __init__(self, store_dir: Path | None = None) -> None:
        """Initialize the store."""
        self._store_dir = store_dir or _get_cow_dir()
        self._pools_path = self._store_dir / "pools.yaml"
        self._datasets_path = self._store_dir / "datasets.yaml"

    def _ensure_dir(self) -> None:
        """Ensure store directory exists with proper permissions."""
        self._store_dir.mkdir(parents=True, exist_ok=True)
        os.chmod(self._store_dir, stat.S_IRWXU)  # 700

    def _load_pools(self) -> PoolsStore:
        """Load pools from disk."""
        if not self._pools_path.exists():
            return PoolsStore()

        with open(self._pools_path) as f:
            data = yaml.safe_load(f) or {}

        return PoolsStore.model_validate(data)

    def _save_pools(self, store: PoolsStore) -> None:
        """Save pools to disk."""
        self._ensure_dir()

        temp_path = self._pools_path.with_suffix(".tmp")
        with open(temp_path, "w") as f:
            yaml.dump(store.model_dump(mode="json"), f, default_flow_style=False)

        os.chmod(temp_path, stat.S_IRUSR | stat.S_IWUSR)  # 600
        temp_path.rename(self._pools_path)

    def _load_datasets(self) -> DatasetsStore:
        """Load datasets from disk."""
        if not self._datasets_path.exists():
            return DatasetsStore()

        with open(self._datasets_path) as f:
            data = yaml.safe_load(f) or {}

        return DatasetsStore.model_validate(data)

    def _save_datasets(self, store: DatasetsStore) -> None:
        """Save datasets to disk."""
        self._ensure_dir()

        temp_path = self._datasets_path.with_suffix(".tmp")
        with open(temp_path, "w") as f:
            yaml.dump(store.model_dump(mode="json"), f, default_flow_style=False)

        os.chmod(temp_path, stat.S_IRUSR | stat.S_IWUSR)  # 600
        temp_path.rename(self._datasets_path)

    # Pool operations

    def save_pool(self, pool: PoolState) -> None:
        """Save or update a pool."""
        store = self._load_pools()
        store.add_pool(pool)
        self._save_pools(store)

    def get_pool(self, name: str) -> PoolState | None:
        """Get a pool by name."""
        store = self._load_pools()
        return store.get_pool(name)

    def delete_pool(self, name: str) -> bool:
        """Delete a pool."""
        store = self._load_pools()
        if store.remove_pool(name):
            self._save_pools(store)
            return True
        return False

    def list_pools(self) -> list[PoolState]:
        """List all pools."""
        store = self._load_pools()
        return store.list_pools()

    def pool_exists(self, name: str) -> bool:
        """Check if a pool exists."""
        return self.get_pool(name) is not None

    # Dataset operations

    def save_dataset(self, dataset: DatasetState) -> None:
        """Save or update a dataset."""
        store = self._load_datasets()
        store.add_dataset(dataset)
        self._save_datasets(store)

    def get_dataset(self, pool: str, name: str) -> DatasetState | None:
        """Get a dataset by pool/name."""
        store = self._load_datasets()
        return store.get_dataset(pool, name)

    def delete_dataset(self, pool: str, name: str) -> bool:
        """Delete a dataset."""
        store = self._load_datasets()
        if store.remove_dataset(pool, name):
            self._save_datasets(store)
            return True
        return False

    def list_datasets(self, pool: str | None = None) -> list[DatasetState]:
        """List all datasets, optionally filtered by pool."""
        store = self._load_datasets()
        return store.list_datasets(pool)

    def dataset_exists(self, pool: str, name: str) -> bool:
        """Check if a dataset exists."""
        return self.get_dataset(pool, name) is not None

    def get_datasets_for_pool(self, pool: str) -> list[DatasetState]:
        """Get all datasets for a pool."""
        return self.list_datasets(pool)

    def count_datasets_for_pool(self, pool: str) -> int:
        """Count datasets in a pool."""
        return len(self.get_datasets_for_pool(pool))
