"""Review state checking and utilities.

This module centralizes logic that was previously duplicated across CLI commands:
- Checking if a reviewed module has changed (is "stale")
- Extracting issue numbers from various formats
- Categorizing modules by their effective status
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING

from .git import has_changes_since

if TYPE_CHECKING:
    from .config import Config
    from .registry import ModuleStatus, Registry


@dataclass
class ModuleStateInfo:
    """Extended state information for a module."""

    module: "ModuleStatus"
    is_stale: bool = False
    stale_error: str | None = None  # Error message if stale check failed

    @property
    def effective_status(self) -> str:
        """Get effective status considering staleness.

        A reviewed module that has changed is effectively 'needs_re_review'.
        """
        if self.module.status == "reviewed" and self.is_stale:
            return "needs_re_review"
        return self.module.status


@dataclass
class RegistryStateInfo:
    """Categorized view of registry state."""

    in_progress: list[ModuleStateInfo]
    needs_review: list[ModuleStateInfo]
    reviewed_current: list[ModuleStateInfo]  # Reviewed and up to date
    reviewed_stale: list[ModuleStateInfo]  # Reviewed but changed

    @property
    def total(self) -> int:
        return (
            len(self.in_progress)
            + len(self.needs_review)
            + len(self.reviewed_current)
            + len(self.reviewed_stale)
        )

    @property
    def reviewed_count(self) -> int:
        """Count of reviewed modules (current only, not stale)."""
        return len(self.reviewed_current)

    @property
    def total_lines(self) -> int:
        """Total lines across all modules."""
        total = 0
        for info in (
            self.in_progress
            + self.needs_review
            + self.reviewed_current
            + self.reviewed_stale
        ):
            total += info.module.lines
        return total

    @property
    def reviewed_lines(self) -> int:
        """Lines in reviewed (current) modules only."""
        return sum(info.module.lines for info in self.reviewed_current)


class ReviewStateChecker:
    """Centralized logic for checking review state.

    This class eliminates duplication of:
    - Stale module detection (was in status, check, report commands)
    - Issue number extraction (was in signoff, cancel, claude-review commands)
    """

    def __init__(self, config: "Config"):
        self.config = config

    def is_module_stale(self, module: "ModuleStatus") -> tuple[bool, str | None]:
        """Check if a reviewed module has changes since last review.

        Args:
            module: The module to check.

        Returns:
            Tuple of (is_stale, error_message).
            error_message is set if the check couldn't be performed reliably.
        """
        if module.status != "reviewed":
            return False, None

        if not module.last_reviewed_commit:
            # Reviewed but no commit recorded - treat as stale
            return True, "No review commit recorded"

        try:
            changed = has_changes_since(
                module.path,
                module.last_reviewed_commit,
                cwd=self.config.root,
            )
            return changed, None
        except Exception as e:
            # Can't determine - report error but assume stale to be safe
            return True, str(e)

    def get_module_state(self, module: "ModuleStatus") -> ModuleStateInfo:
        """Get extended state info for a module."""
        is_stale, error = self.is_module_stale(module)
        return ModuleStateInfo(
            module=module,
            is_stale=is_stale,
            stale_error=error,
        )

    def get_registry_state(self, registry: "Registry") -> RegistryStateInfo:
        """Categorize all modules in registry by their effective state.

        This provides a single source of truth for module categorization,
        replacing duplicated logic in status, check, and report commands.
        """
        in_progress = []
        needs_review = []
        reviewed_current = []
        reviewed_stale = []

        for module in registry:
            info = self.get_module_state(module)

            if module.status == "in_progress":
                in_progress.append(info)
            elif module.status == "needs_review":
                needs_review.append(info)
            elif module.status == "reviewed":
                if info.is_stale:
                    reviewed_stale.append(info)
                else:
                    reviewed_current.append(info)
            # Note: 'needs_update' status is not used - see state_machine.py

        return RegistryStateInfo(
            in_progress=in_progress,
            needs_review=needs_review,
            reviewed_current=reviewed_current,
            reviewed_stale=reviewed_stale,
        )

    @staticmethod
    def extract_issue_number(review_issue: str | None) -> str | None:
        """Extract issue number from various formats.

        Handles:
        - "123" -> "123"
        - "#123" -> "123"
        - "https://gitlab.com/org/project/-/issues/123" -> "123"
        - "https://gitlab.com/org/project/-/issues/123/" -> "123"

        Args:
            review_issue: The stored issue reference.

        Returns:
            Just the issue number, or None if not parseable.
        """
        if not review_issue:
            return None

        review_issue = review_issue.strip()

        if review_issue.startswith("#"):
            return review_issue[1:]

        if "/" in review_issue:
            # URL format - extract last path component
            return review_issue.rstrip("/").split("/")[-1]

        # Assume it's just the number
        return review_issue

    @staticmethod
    def format_issue_link(review_issue: str | None) -> str:
        """Format issue reference for display.

        Returns markdown link if URL, otherwise just the reference.
        """
        if not review_issue:
            return "-"

        if "/" in review_issue and review_issue.startswith("http"):
            # Full URL - create markdown link
            number = ReviewStateChecker.extract_issue_number(review_issue)
            return f"[#{number}]({review_issue})"

        if review_issue.startswith("#"):
            return review_issue

        return f"#{review_issue}"
