"""
Strategic Roadmap - SST-driven strategic initiative tracking.

This module provides the schema layer for tracking strategic initiatives
derived from competitive analysis and market positioning.

Key Concepts:
    - StrategicEpic: A major initiative with multiple tasks
    - StrategicTask: Individual work items within an epic
    - StrategicDecision: Explicit documentation of what NOT to build
    - StrategicTestSpec: Test specifications derived from strategic requirements
    - RoadmapTimeline: Quarterly planning with milestones

Usage:
    from lightwave.schema.pydantic.sst import (
        StrategicRoadmap,
        StrategicEpic,
        StrategicTask,
    )

    # Load roadmap from SST
    roadmap = StrategicRoadmap.from_sst()

    # Get all epics
    for epic in roadmap.get_active_epics():
        print(f"{epic.name}: {len(epic.tasks)} tasks")

    # Get tasks for testing
    test_specs = roadmap.get_test_specs()
"""

from __future__ import annotations

from dataclasses import dataclass
from enum import Enum
from functools import lru_cache

import yaml
from pydantic import BaseModel, ConfigDict, Field

# =============================================================================
# ENUMS
# =============================================================================


class EpicPriority(str, Enum):
    """Strategic priority levels."""

    P0 = "p0"  # Critical - do now
    P1 = "p1"  # High - this quarter
    P2 = "p2"  # Medium - next quarter
    P3 = "p3"  # Low - future consideration


class EpicStatus(str, Enum):
    """Epic lifecycle status."""

    PLANNING = "planning"
    ACTIVE = "active"
    COMPLETED = "completed"
    DEFERRED = "deferred"
    CANCELLED = "cancelled"


class TaskType(str, Enum):
    """Strategic task types."""

    FEATURE = "feature"
    SPIKE = "spike"
    DOCS = "docs"
    RESEARCH = "research"
    CHORE = "chore"


class TaskPriority(str, Enum):
    """Task priority within epic."""

    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"


class TaskEffort(str, Enum):
    """Estimated effort for task."""

    TRIVIAL = "trivial"  # < 5 minutes
    QUICK = "quick"  # 5-15 minutes
    MEDIUM = "medium"  # 15-60 minutes
    DEEP = "deep"  # 1+ hours


class TaskCategory(str, Enum):
    """Task category for grouping."""

    SST_ALIGNMENT = "sst_alignment"
    DOMAIN_VERTICAL = "domain_vertical"
    DOCUMENTATION = "documentation"
    MARKETING = "marketing"
    RESEARCH = "research"
    INFRASTRUCTURE = "infrastructure"


class SpecTestType(str, Enum):
    """Test specification types."""

    UNIT = "unit"
    INTEGRATION = "integration"
    CONTRACT = "contract"
    E2E = "e2e"
    DOCUMENTATION = "documentation"


# =============================================================================
# TASK SCHEMAS
# =============================================================================


class StrategicTask(BaseModel):
    """A task within a strategic epic."""

    model_config = ConfigDict(extra="forbid")

    id: str = Field(..., description="Unique task identifier")
    name: str = Field(..., description="Task name")
    description: str = Field(..., description="What this task accomplishes")
    type: TaskType = Field(..., description="Type of task")
    priority: TaskPriority = Field(..., description="Priority within epic")
    effort: TaskEffort = Field(..., description="Estimated effort")
    category: TaskCategory = Field(..., description="Task category")
    depends_on: list[str] = Field(default_factory=list, description="Task IDs this depends on")
    acceptance_criteria: list[str] = Field(default_factory=list, description="Definition of done")


class SuccessMetric(BaseModel):
    """A measurable success metric for an epic."""

    model_config = ConfigDict(extra="forbid")

    metric: str = Field(..., description="Metric name")
    target: int | float = Field(..., description="Target value")
    unit: str = Field(..., description="Unit of measurement")


# =============================================================================
# EPIC SCHEMAS
# =============================================================================


class StrategicEpic(BaseModel):
    """A strategic initiative with multiple tasks."""

    model_config = ConfigDict(extra="forbid")

    id: str = Field(..., description="Unique epic identifier")
    name: str = Field(..., description="Epic name")
    description: str = Field(..., description="What this epic accomplishes")
    priority: EpicPriority = Field(..., description="Strategic priority")
    status: EpicStatus = Field(..., description="Current status")
    strategic_rationale: str = Field(..., description="Why this matters strategically")
    success_metrics: list[SuccessMetric] = Field(default_factory=list)
    principles_alignment: list[str] = Field(default_factory=list, description="Aligned principle IDs")
    tasks: list[StrategicTask] = Field(default_factory=list)
    defer_until: str | None = Field(None, description="Quarter to defer until")

    @property
    def total_tasks(self) -> int:
        """Total number of tasks in this epic."""
        return len(self.tasks)

    @property
    def high_priority_tasks(self) -> list[StrategicTask]:
        """Tasks marked as high priority."""
        return [t for t in self.tasks if t.priority == TaskPriority.HIGH]

    def get_tasks_by_category(self, category: TaskCategory) -> list[StrategicTask]:
        """Get tasks filtered by category."""
        return [t for t in self.tasks if t.category == category]


# =============================================================================
# STRATEGIC DECISION SCHEMAS
# =============================================================================


class StrategicDecision(BaseModel):
    """An explicit decision about what NOT to build."""

    model_config = ConfigDict(extra="forbid")

    id: str = Field(..., description="Decision identifier")
    name: str = Field(..., description="Decision name")
    rationale: str = Field(..., description="Why we made this decision")
    revisit_when: str | None = Field(None, description="Conditions to revisit")
    instead: str | None = Field(None, description="What we're doing instead")


class NotBuildingEpic(BaseModel):
    """Epic for tracking strategic non-features."""

    model_config = ConfigDict(extra="forbid")

    id: str
    name: str
    description: str
    priority: EpicPriority
    status: EpicStatus
    strategic_rationale: str
    decisions: list[StrategicDecision] = Field(default_factory=list)


# =============================================================================
# COMPETITIVE POSITIONING
# =============================================================================


class Differentiator(BaseModel):
    """A unique differentiator vs competitors."""

    model_config = ConfigDict(extra="forbid")

    id: str
    name: str
    description: str
    competitor_gap: str = Field(..., description="What competitors lack")


class PositioningAxis(BaseModel):
    """A positioning axis in the competitive landscape."""

    model_config = ConfigDict(extra="forbid")

    name: str
    our_position: str
    competitors: dict[str, str] = Field(default_factory=dict)


class CompetitivePositioning(BaseModel):
    """Our strategic positioning vs competitors."""

    model_config = ConfigDict(extra="forbid")

    primary_axis: PositioningAxis
    secondary_axis: PositioningAxis
    unique_differentiators: list[Differentiator] = Field(default_factory=list)


# =============================================================================
# TEST SPECIFICATIONS
# =============================================================================


class StrategicTestSpec(BaseModel):
    """A test specification derived from strategic requirements."""

    model_config = ConfigDict(extra="forbid")

    id: str = Field(..., description="Spec ID (e.g., STRAT-TEMPLATE-001)")
    epic: str = Field(..., description="Epic ID this belongs to")
    requirement: str = Field(..., description="What to test")
    test_type: SpecTestType = Field(..., description="Type of test")
    priority: TaskPriority = Field(..., description="Test priority")


# =============================================================================
# TIMELINE
# =============================================================================


class QuarterPlan(BaseModel):
    """Planning for a specific quarter."""

    model_config = ConfigDict(extra="forbid")

    focus: str = Field(..., description="Quarter's strategic focus")
    epics: list[str] = Field(default_factory=list, description="Epic IDs to work on")
    milestones: list[str] = Field(default_factory=list, description="Key milestones")


# =============================================================================
# ROADMAP REGISTRY
# =============================================================================


class StrategicRoadmap(BaseModel):
    """Complete strategic roadmap loaded from SST."""

    model_config = ConfigDict(extra="forbid")

    positioning: CompetitivePositioning
    epics: dict[str, StrategicEpic] = Field(default_factory=dict)
    not_building: NotBuildingEpic | None = None
    test_specs: list[StrategicTestSpec] = Field(default_factory=list)
    timeline: dict[str, QuarterPlan] = Field(default_factory=dict)

    @classmethod
    @lru_cache(maxsize=1)
    def from_sst(cls) -> "StrategicRoadmap":
        """Load strategic roadmap from SST."""
        from lightwave.schema.core.paths import get_sst_path

        yaml_path = get_sst_path("roadmap")
        with open(yaml_path) as f:
            data = yaml.safe_load(f)

        # Parse positioning
        pos_data = data.get("positioning", {})
        positioning = CompetitivePositioning(
            primary_axis=PositioningAxis(**pos_data.get("primary_axis", {})),
            secondary_axis=PositioningAxis(**pos_data.get("secondary_axis", {})),
            unique_differentiators=[Differentiator(**d) for d in pos_data.get("unique_differentiators", [])],
        )

        # Parse epics
        epics = {}
        for epic_key, epic_data in data.get("epics", {}).items():
            if epic_key == "not_building":
                continue  # Handle separately

            # Parse tasks within epic
            tasks = []
            for task_data in epic_data.get("tasks", []):
                tasks.append(StrategicTask(**task_data))

            # Parse success metrics
            metrics = []
            for metric_data in epic_data.get("success_metrics", []):
                metrics.append(SuccessMetric(**metric_data))

            epics[epic_key] = StrategicEpic(
                id=epic_data.get("id", epic_key),
                name=epic_data.get("name", ""),
                description=epic_data.get("description", ""),
                priority=EpicPriority(epic_data.get("priority", "p2")),
                status=EpicStatus(epic_data.get("status", "planning")),
                strategic_rationale=epic_data.get("strategic_rationale", ""),
                success_metrics=metrics,
                principles_alignment=epic_data.get("principles_alignment", []),
                tasks=tasks,
                defer_until=epic_data.get("defer_until"),
            )

        # Parse not_building epic
        not_building = None
        if "not_building" in data.get("epics", {}):
            nb_data = data["epics"]["not_building"]
            decisions = [StrategicDecision(**d) for d in nb_data.get("decisions", [])]
            not_building = NotBuildingEpic(
                id=nb_data.get("id", "not_building"),
                name=nb_data.get("name", ""),
                description=nb_data.get("description", ""),
                priority=EpicPriority(nb_data.get("priority", "p0")),
                status=EpicStatus(nb_data.get("status", "active")),
                strategic_rationale=nb_data.get("strategic_rationale", ""),
                decisions=decisions,
            )

        # Parse test specs
        test_specs = []
        specs_data = data.get("test_specs", {}).get("specs", [])
        for spec_data in specs_data:
            test_specs.append(StrategicTestSpec(**spec_data))

        # Parse timeline
        timeline = {}
        for quarter, quarter_data in data.get("timeline", {}).items():
            timeline[quarter] = QuarterPlan(**quarter_data)

        return cls(
            positioning=positioning,
            epics=epics,
            not_building=not_building,
            test_specs=test_specs,
            timeline=timeline,
        )

    def get_epic(self, epic_id: str) -> StrategicEpic:
        """Get an epic by ID."""
        if epic_id not in self.epics:
            available = list(self.epics.keys())
            raise KeyError(f"Epic '{epic_id}' not found. Available: {available}")
        return self.epics[epic_id]

    def get_active_epics(self) -> list[StrategicEpic]:
        """Get all active epics."""
        return [e for e in self.epics.values() if e.status == EpicStatus.ACTIVE]

    def get_planning_epics(self) -> list[StrategicEpic]:
        """Get all epics in planning status."""
        return [e for e in self.epics.values() if e.status == EpicStatus.PLANNING]

    def get_epics_by_priority(self, priority: EpicPriority) -> list[StrategicEpic]:
        """Get epics filtered by priority."""
        return [e for e in self.epics.values() if e.priority == priority]

    def get_all_tasks(self) -> list[StrategicTask]:
        """Get all tasks across all epics."""
        tasks = []
        for epic in self.epics.values():
            tasks.extend(epic.tasks)
        return tasks

    def get_high_priority_tasks(self) -> list[StrategicTask]:
        """Get all high priority tasks across all epics."""
        return [t for t in self.get_all_tasks() if t.priority == TaskPriority.HIGH]

    def get_test_specs_for_epic(self, epic_id: str) -> list[StrategicTestSpec]:
        """Get test specs for a specific epic."""
        return [s for s in self.test_specs if s.epic == epic_id]

    def get_quarter_plan(self, quarter: str) -> QuarterPlan | None:
        """Get plan for a specific quarter."""
        return self.timeline.get(quarter)

    def get_differentiators(self) -> list[Differentiator]:
        """Get all unique differentiators."""
        return self.positioning.unique_differentiators


# =============================================================================
# CONVENIENCE FUNCTIONS
# =============================================================================


def get_strategic_roadmap() -> StrategicRoadmap:
    """Get the strategic roadmap (cached)."""
    return StrategicRoadmap.from_sst()


def get_all_strategic_tasks() -> list[StrategicTask]:
    """Get all strategic tasks across all epics."""
    roadmap = get_strategic_roadmap()
    return roadmap.get_all_tasks()


def get_strategic_test_specs() -> list[StrategicTestSpec]:
    """Get all test specifications from strategic roadmap."""
    roadmap = get_strategic_roadmap()
    return roadmap.test_specs


# =============================================================================
# SUMMARY DATACLASSES
# =============================================================================


@dataclass
class RoadmapSummary:
    """Summary statistics for the strategic roadmap."""

    total_epics: int
    active_epics: int
    planning_epics: int
    total_tasks: int
    high_priority_tasks: int
    total_test_specs: int
    differentiators: int
    strategic_decisions: int

    @classmethod
    def from_roadmap(cls, roadmap: StrategicRoadmap) -> "RoadmapSummary":
        """Generate summary from a roadmap."""
        return cls(
            total_epics=len(roadmap.epics),
            active_epics=len(roadmap.get_active_epics()),
            planning_epics=len(roadmap.get_planning_epics()),
            total_tasks=len(roadmap.get_all_tasks()),
            high_priority_tasks=len(roadmap.get_high_priority_tasks()),
            total_test_specs=len(roadmap.test_specs),
            differentiators=len(roadmap.positioning.unique_differentiators),
            strategic_decisions=len(roadmap.not_building.decisions) if roadmap.not_building else 0,
        )


def get_roadmap_summary() -> RoadmapSummary:
    """Get summary of the strategic roadmap."""
    roadmap = get_strategic_roadmap()
    return RoadmapSummary.from_roadmap(roadmap)


# =============================================================================
# MODULE EXPORTS
# =============================================================================

__all__ = [
    # Enums
    "EpicPriority",
    "EpicStatus",
    "TaskType",
    "TaskPriority",
    "TaskEffort",
    "TaskCategory",
    "SpecTestType",
    # Task schemas
    "StrategicTask",
    "SuccessMetric",
    # Epic schemas
    "StrategicEpic",
    # Decision schemas
    "StrategicDecision",
    "NotBuildingEpic",
    # Positioning schemas
    "Differentiator",
    "PositioningAxis",
    "CompetitivePositioning",
    # Test specs
    "StrategicTestSpec",
    # Timeline
    "QuarterPlan",
    # Roadmap
    "StrategicRoadmap",
    # Summary
    "RoadmapSummary",
    # Functions
    "get_strategic_roadmap",
    "get_all_strategic_tasks",
    "get_strategic_test_specs",
    "get_roadmap_summary",
]
