"""
Issue tracker abstraction module.

Defines a protocol and backend implementations for issue tracker commands.
"""

from __future__ import annotations

import logging
import os
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Protocol, runtime_checkable

from ..utils.env_vars import get_env_with_fallback

if TYPE_CHECKING:
    from maniple_mcp.config import ClaudeTeamConfig

logger = logging.getLogger("maniple")

# Environment variables for explicit tracker override (highest priority).
ISSUE_TRACKER_ENV_VAR = "MANIPLE_ISSUE_TRACKER"
ISSUE_TRACKER_ENV_VAR_FALLBACK = "CLAUDE_TEAM_ISSUE_TRACKER"


@runtime_checkable
class IssueTrackerBackend(Protocol):
    """
    Protocol defining the issue tracker backend interface.

    Backends provide a name, CLI command, marker directory, and command templates.
    """

    name: str
    cli: str
    marker_dir: str
    commands: dict[str, str]


@dataclass(frozen=True)
class BeadsBackend:
    """Beads issue tracker backend."""

    name: str = "beads"
    cli: str = "bd"
    marker_dir: str = ".beads"
    commands: dict[str, str] = field(
        default_factory=lambda: {
            "list": "bd --no-db list",
            "ready": "bd --no-db ready",
            "show": "bd --no-db show {issue_id}",
            "update": "bd --no-db update {issue_id} --status {status}",
            "close": "bd --no-db close {issue_id}",
            "create": (
                "bd --no-db create --title \"{title}\" --type {type} "
                "--priority {priority} --description \"{description}\""
            ),
            "comment": "bd --no-db comment {issue_id} \"{comment}\"",
            "dep_add": "bd --no-db dep add {issue_id} {dependency_id}",
            "dep_tree": "bd --no-db dep tree {issue_id}",
        }
    )


@dataclass(frozen=True)
class PebblesBackend:
    """Pebbles issue tracker backend."""

    name: str = "pebbles"
    cli: str = "pb"
    marker_dir: str = ".pebbles"
    commands: dict[str, str] = field(
        default_factory=lambda: {
            "list": "pb list",
            "ready": "pb ready",
            "show": "pb show {issue_id}",
            "update": "pb update {issue_id} -status {status}",
            "close": "pb close {issue_id}",
            "create": (
                "pb create -title \"{title}\" -type {type} -priority {priority} "
                "-description \"{description}\""
            ),
            "comment": "pb comment {issue_id} -body \"{comment}\"",
            "dep_add": "pb dep add {issue_id} {dependency_id}",
            "dep_tree": "pb dep tree {issue_id}",
        }
    )


BEADS_BACKEND = BeadsBackend()
PEBBLES_BACKEND = PebblesBackend()
BACKEND_REGISTRY: dict[str, IssueTrackerBackend] = {
    BEADS_BACKEND.name: BEADS_BACKEND,
    PEBBLES_BACKEND.name: PEBBLES_BACKEND,
}


def detect_issue_tracker(
    project_path: str,
    config: ClaudeTeamConfig | None = None,
) -> IssueTrackerBackend | None:
    """
    Detect the issue tracker backend for the given project path.

    Resolution order (highest to lowest priority):
      1. MANIPLE_ISSUE_TRACKER environment variable
      2. config.issue_tracker.override setting
      3. Marker directory detection (.pebbles, .beads)

    Args:
        project_path: Absolute or relative path to the project root.
        config: Optional config object. If None, config is loaded from disk.

    Returns:
        The detected IssueTrackerBackend, or None if no tracker is configured
        or detected.
    """
    # Priority 1: Environment variable override.
    env_override = get_env_with_fallback(
        ISSUE_TRACKER_ENV_VAR,
        ISSUE_TRACKER_ENV_VAR_FALLBACK,
    )
    if env_override:
        backend = BACKEND_REGISTRY.get(env_override.lower())
        if backend:
            logger.debug(
                "Using issue tracker '%s' from %s env var",
                backend.name,
                ISSUE_TRACKER_ENV_VAR,
            )
            return backend
        logger.warning(
            "Unknown issue tracker '%s' in %s; ignoring",
            env_override,
            ISSUE_TRACKER_ENV_VAR,
        )

    # Priority 2: Config file override.
    if config is None:
        # Lazy import to avoid circular dependency at module load time.
        try:
            from maniple_mcp.config import ConfigError, load_config

            config = load_config()
        except ConfigError as exc:
            logger.warning("Invalid config file; ignoring overrides: %s", exc)
            config = None

    if config and config.issue_tracker.override:
        backend = BACKEND_REGISTRY.get(config.issue_tracker.override)
        if backend:
            logger.debug(
                "Using issue tracker '%s' from config override",
                backend.name,
            )
            return backend
        # Config validation should prevent this, but handle gracefully.
        logger.warning(
            "Unknown issue tracker '%s' in config; ignoring",
            config.issue_tracker.override,
        )

    # Priority 3: Marker directory detection.
    return _detect_from_markers(project_path)


def _detect_from_markers(project_path: str) -> IssueTrackerBackend | None:
    """Detect issue tracker by checking for marker directories."""
    beads_marker = os.path.join(project_path, BEADS_BACKEND.marker_dir)
    pebbles_marker = os.path.join(project_path, PEBBLES_BACKEND.marker_dir)

    # Check marker directories in the project root.
    beads_present = os.path.isdir(beads_marker)
    pebbles_present = os.path.isdir(pebbles_marker)

    # Resolve the deterministic backend when both markers exist.
    if beads_present and pebbles_present:
        logger.warning(
            "Both .beads and .pebbles found in %s; defaulting to pebbles",
            project_path,
        )
        return PEBBLES_BACKEND

    # Return the matching backend if only one marker exists.
    if pebbles_present:
        return PEBBLES_BACKEND

    if beads_present:
        return BEADS_BACKEND

    return None


__all__ = [
    "IssueTrackerBackend",
    "BeadsBackend",
    "PebblesBackend",
    "BEADS_BACKEND",
    "PEBBLES_BACKEND",
    "BACKEND_REGISTRY",
    "ISSUE_TRACKER_ENV_VAR",
    "detect_issue_tracker",
]
