"""Data types for campaign orchestration results.

These dataclasses represent the results and intermediate states
of campaign lifecycle operations.
"""

from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path

from unfamiliar.constants import CampaignStatus, InvestigationCategory


class CampaignExistsError(Exception):
    """Raised when creating a campaign for a repo that already has an active one.

    Purpose: Signal to CLI layer that user confirmation is needed before
    overwriting an existing campaign with progress.

    Attributes:
        campaign_dir: Path to existing campaign directory.
        completed_count: Number of completed missions in existing campaign.
        total_count: Total missions in existing campaign.
    """

    def __init__(
        self,
        campaign_dir: Path,
        completed_count: int,
        total_count: int,
    ) -> None:
        self.campaign_dir = campaign_dir
        self.completed_count = completed_count
        self.total_count = total_count
        super().__init__(
            f"Campaign already exists at {campaign_dir} with "
            f"{completed_count}/{total_count} missions completed. "
            f"Use --force to overwrite."
        )


@dataclass
class CampaignInfo:
    """Metadata for a discovered campaign.

    Returned by discover_campaigns() when scanning the campaigns directory.
    Used by the CLI to list available campaigns.

    Attributes:
        campaign_dir: Path to the campaign's storage directory.
        repo_path: Path to the repository (None if orphaned/missing marker).
        status: Current campaign lifecycle state.
        is_orphaned: True if the repo path no longer exists on filesystem.
        created_at: When the campaign was created.
        updated_at: When the campaign was last modified.
        mission_count: Total number of missions in the campaign.
        completed_count: Number of completed missions.
    """

    campaign_dir: Path
    repo_path: Path | None
    status: CampaignStatus
    is_orphaned: bool
    created_at: datetime | None
    updated_at: datetime | None
    mission_count: int
    completed_count: int


@dataclass
class PersistResult:
    """Result of persisting pipeline data to the database.

    Returned by persist_pipeline_data() after transforming and storing
    all LLM-generated missions, chains, and relationships.

    Attributes:
        mission_count: Total number of missions persisted.
        chain_count: Total number of chains persisted.
        warning_messages: List of non-fatal issues encountered during persistence.
    """

    mission_count: int
    chain_count: int
    warning_messages: list[str] = field(default_factory=list)


@dataclass
class CompletionResult:
    """Result of completing a mission.

    Returned by complete_mission() after marking a mission as complete
    and unlocking any dependent missions.

    Attributes:
        mission_id: The ID of the completed mission.
        unlocked_ids: List of mission IDs that were transitioned to AVAILABLE.
    """

    mission_id: int
    unlocked_ids: list[int] = field(default_factory=list)


@dataclass
class CategoryProgress:
    """Progress statistics for a single investigation category.

    Attributes:
        category: The investigation category this tracks.
        total: Total missions in this category.
        completed: Number of completed missions.
        available: Number of missions ready to start (AVAILABLE status).
        locked: Number of missions with unmet prerequisites (LOCKED status).
        percent: Completion percentage (0-100).
    """

    category: InvestigationCategory
    total: int
    completed: int
    available: int
    locked: int
    percent: int


@dataclass
class CampaignProgress:
    """Overall progress statistics for a campaign.

    Aggregates mission status across all categories and provides
    both per-category and overall completion metrics.

    Attributes:
        category_progress: Progress for each of the 7 categories.
        total_missions: Sum of all missions across all categories.
        completed_missions: Total completed missions.
        available_missions: Missions ready to start.
        locked_missions: Missions with unmet prerequisites.
        in_progress_missions: Missions currently in progress.
        overall_percent: Overall completion percentage (0-100).
        security_total: Total security-tagged missions.
        security_completed: Completed security-tagged missions.
    """

    category_progress: list[CategoryProgress]
    total_missions: int
    completed_missions: int
    available_missions: int
    locked_missions: int
    in_progress_missions: int
    overall_percent: int
    security_total: int
    security_completed: int
