"""Run Instance Manager

Responsible for creating, finding, listing, and archiving run instances
"""

import json
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional

from .exceptions import FileSystemError, InvalidRunIDError, RunNotFoundError
from .models import RunInstance, RunStatus
from .utils import ensure_directory_exists, generate_theme_slug, is_valid_run_id


class RunManager:
    """Run Instance Manager"""

    def __init__(self, projects_dir: Path):
        """Initialize manager

        Args:
            projects_dir: projects directory path
        """
        self.projects_dir = projects_dir
        ensure_directory_exists(projects_dir)

    def create_run(self, theme_description: str, run_id: Optional[str] = None) -> RunInstance:
        """Create new run instance

        Args:
            theme_description: task description
            run_id: optional custom run_id (auto-generated by default)

        Returns:
            RunInstance instance

        Raises:
            InvalidRunIDError: run_id format is invalid
            FileSystemError: directory creation failed
        """
        # Generate or validate run_id (always add date prefix)
        from datetime import datetime as dt
        date_prefix = dt.now().strftime("%Y%m%d")

        if run_id is None:
            run_id = generate_theme_slug(theme_description)
        else:
            if not is_valid_run_id(run_id):
                raise InvalidRunIDError(run_id, "format must be lowercase letters, numbers, hyphens, length 1-100")
            # Custom run_id also gets date prefix (if not already present)
            if not run_id.startswith(date_prefix):
                run_id = f"{date_prefix}-{run_id}"

        run_dir = self.projects_dir / run_id
        now = datetime.now()

        # Create directory structure
        ensure_directory_exists(run_dir)
        ensure_directory_exists(run_dir / "logs")
        ensure_directory_exists(run_dir / "screenshots")
        ensure_directory_exists(run_dir / "scripts")
        ensure_directory_exists(run_dir / "outputs")

        # Create RunInstance
        instance = RunInstance(
            run_id=run_id,
            theme_description=theme_description,
            created_at=now,
            last_accessed=now,
            status=RunStatus.ACTIVE,
        )

        # Write .metadata.json
        metadata_file = run_dir / ".metadata.json"
        try:
            metadata_file.write_text(json.dumps(instance.to_dict(), indent=2))
        except Exception as e:
            raise FileSystemError("write", str(metadata_file), str(e))

        return instance

    def find_run(self, run_id: str) -> RunInstance:
        """Find run instance

        Args:
            run_id: run ID

        Returns:
            RunInstance instance

        Raises:
            RunNotFoundError: run does not exist
            FileSystemError: metadata read failed
        """
        run_dir = self.projects_dir / run_id
        if not run_dir.exists() or not run_dir.is_dir():
            raise RunNotFoundError(run_id)

        metadata_file = run_dir / ".metadata.json"
        if not metadata_file.exists():
            raise FileSystemError("read", str(metadata_file), "Metadata file not found")

        try:
            data = json.loads(metadata_file.read_text())
            return RunInstance.from_dict(data)
        except Exception as e:
            raise FileSystemError("read", str(metadata_file), str(e))

    def list_runs(
        self, status: Optional[RunStatus] = None
    ) -> List[Dict]:
        """List all run instances

        Args:
            status: filter status (None means all)

        Returns:
            list of run information (including statistics)
        """
        if not self.projects_dir.exists():
            return []

        runs = []
        for run_dir in self.projects_dir.iterdir():
            if not run_dir.is_dir():
                continue

            metadata_file = run_dir / ".metadata.json"
            if not metadata_file.exists():
                continue

            try:
                data = json.loads(metadata_file.read_text())
                instance = RunInstance.from_dict(data)

                # Status filter
                if status and instance.status != status:
                    continue

                # Statistics
                from .logger import RunLogger

                logger = RunLogger(run_dir)
                log_count = logger.count_logs()
                screenshot_count = len(list((run_dir / "screenshots").glob("*.png")))

                runs.append(
                    {
                        "run_id": instance.run_id,
                        "status": instance.status.value,
                        "created_at": instance.created_at.isoformat().replace("+00:00", "Z"),
                        "last_accessed": instance.last_accessed.isoformat().replace(
                            "+00:00", "Z"
                        ),
                        "theme_description": instance.theme_description,
                        "log_count": log_count,
                        "screenshot_count": screenshot_count,
                    }
                )
            except Exception:
                continue  # Skip corrupted run

        # Sort by last accessed time in descending order
        runs.sort(key=lambda r: r["last_accessed"], reverse=True)

        return runs

    def archive_run(self, run_id: str) -> RunInstance:
        """Archive run instance

        Args:
            run_id: run ID

        Returns:
            RunInstance instance

        Raises:
            RunNotFoundError: run does not exist
            FileSystemError: metadata update failed
        """
        instance = self.find_run(run_id)
        instance.status = RunStatus.ARCHIVED

        metadata_file = self.projects_dir / run_id / ".metadata.json"
        try:
            metadata_file.write_text(json.dumps(instance.to_dict(), indent=2))
        except Exception as e:
            raise FileSystemError("write", str(metadata_file), str(e))

        return instance

    def get_run_statistics(self, run_id: str) -> Dict:
        """Get run instance statistics

        Args:
            run_id: run ID

        Returns:
            statistics dictionary
        """
        instance = self.find_run(run_id)
        run_dir = self.projects_dir / run_id

        from .logger import RunLogger

        logger = RunLogger(run_dir)

        # Count files
        screenshot_count = len(list((run_dir / "screenshots").glob("*.png")))
        script_count = sum(
            1
            for p in (run_dir / "scripts").iterdir()
            if p.is_file() and p.suffix in [".py", ".js", ".sh"]
        )

        # Calculate disk usage
        disk_usage = sum(f.stat().st_size for f in run_dir.rglob("*") if f.is_file())

        return {
            "log_entries": logger.count_logs(),
            "screenshots": screenshot_count,
            "scripts": script_count,
            "disk_usage_bytes": disk_usage,
        }
