"""Persistent storage for container groups."""

from __future__ import annotations

from datetime import datetime
from pathlib import Path

import yaml
from pydantic import BaseModel

from gaol.config import get_config_dir
from gaol.groups.models import GroupSpec, GroupState


class StoredGroup(BaseModel):
    """Stored group specification with metadata."""

    spec: GroupSpec
    state: GroupState = GroupState.CREATED
    network_name: str | None = None
    container_ids: dict[str, str] = {}  # container_name -> container_id
    created_at: datetime
    updated_at: datetime
    started_at: datetime | None = None
    stopped_at: datetime | None = None


class GroupStore:
    """Persistent storage for container groups.

    Groups are stored as YAML files in ~/.config/gaol/groups/
    """

    def __init__(self, store_dir: Path | None = None) -> None:
        """Initialize the group store.

        Args:
            store_dir: Directory to store group configs. Defaults to
                       ~/.config/gaol/groups/
        """
        if store_dir is None:
            store_dir = get_config_dir() / "groups"
        self._store_dir = store_dir
        self._store_dir.mkdir(parents=True, exist_ok=True)

    def _get_path(self, name: str) -> Path:
        """Get the path for a group config file."""
        return self._store_dir / f"{name}.yaml"

    def save(
        self,
        spec: GroupSpec,
        state: GroupState = GroupState.CREATED,
        network_name: str | None = None,
        container_ids: dict[str, str] | None = None,
    ) -> StoredGroup:
        """Save a group specification.

        Args:
            spec: Group specification to save
            state: Current state of the group
            network_name: Name of the shared network (if created)
            container_ids: Mapping of container names to runtime IDs

        Returns:
            The stored group record
        """
        path = self._get_path(spec.name)
        now = datetime.now()

        # Check if already exists to preserve timestamps
        existing = self.get(spec.name)
        if existing:
            stored = StoredGroup(
                spec=spec,
                state=state,
                network_name=network_name or existing.network_name,
                container_ids=container_ids or existing.container_ids,
                created_at=existing.created_at,
                updated_at=now,
                started_at=existing.started_at,
                stopped_at=existing.stopped_at,
            )
        else:
            stored = StoredGroup(
                spec=spec,
                state=state,
                network_name=network_name,
                container_ids=container_ids or {},
                created_at=now,
                updated_at=now,
            )

        # Write to file
        data = stored.model_dump(mode="json")
        path.write_text(yaml.dump(data, default_flow_style=False, sort_keys=False))
        return stored

    def get(self, name: str) -> StoredGroup | None:
        """Get a stored group.

        Args:
            name: Group name

        Returns:
            StoredGroup if found, None otherwise
        """
        path = self._get_path(name)
        if not path.exists():
            return None

        data = yaml.safe_load(path.read_text())
        return StoredGroup(**data)

    def list(self, include_stopped: bool = True) -> list[StoredGroup]:
        """List all stored groups.

        Args:
            include_stopped: Include stopped groups in the list

        Returns:
            List of stored groups
        """
        groups = []
        for path in self._store_dir.glob("*.yaml"):
            try:
                data = yaml.safe_load(path.read_text())
                group = StoredGroup(**data)
                if include_stopped or group.state not in (
                    GroupState.STOPPED,
                    GroupState.CREATED,
                ):
                    groups.append(group)
            except Exception:
                # Skip invalid files
                continue
        return sorted(groups, key=lambda g: g.spec.name)

    def delete(self, name: str) -> bool:
        """Delete a stored group.

        Args:
            name: Group name

        Returns:
            True if deleted, False if not found
        """
        path = self._get_path(name)
        if path.exists():
            path.unlink()
            return True
        return False

    def exists(self, name: str) -> bool:
        """Check if a group exists.

        Args:
            name: Group name

        Returns:
            True if exists
        """
        return self._get_path(name).exists()

    def update_state(
        self,
        name: str,
        state: GroupState,
        network_name: str | None = None,
        container_ids: dict[str, str] | None = None,
    ) -> StoredGroup | None:
        """Update the state of a group.

        Args:
            name: Group name
            state: New state
            network_name: Updated network name (optional)
            container_ids: Updated container IDs (optional)

        Returns:
            Updated StoredGroup or None if not found
        """
        stored = self.get(name)
        if not stored:
            return None

        now = datetime.now()
        stored.state = state
        stored.updated_at = now

        if network_name is not None:
            stored.network_name = network_name

        if container_ids is not None:
            stored.container_ids = container_ids

        # Track start/stop times
        if state == GroupState.RUNNING:
            stored.started_at = now
        elif state == GroupState.STOPPED:
            stored.stopped_at = now

        # Write back
        path = self._get_path(name)
        data = stored.model_dump(mode="json")
        path.write_text(yaml.dump(data, default_flow_style=False, sort_keys=False))
        return stored

    def update_container_id(self, name: str, container_name: str, container_id: str) -> None:
        """Update a specific container's ID.

        Args:
            name: Group name
            container_name: Name of container within the group
            container_id: Runtime container ID
        """
        stored = self.get(name)
        if stored:
            stored.container_ids[container_name] = container_id
            stored.updated_at = datetime.now()
            path = self._get_path(name)
            data = stored.model_dump(mode="json")
            path.write_text(yaml.dump(data, default_flow_style=False, sort_keys=False))


# Global store instance
_store: GroupStore | None = None


def get_group_store() -> GroupStore:
    """Get the global group store instance."""
    global _store
    if _store is None:
        _store = GroupStore()
    return _store
