#!/usr/bin/env python3
"""
How-To Guide Builder (C3.3) - Build step-by-step guides from workflow examples

Transforms multi-step test workflows (from C3.2) into educational "how to" guides with:
- Step-by-step breakdowns
- Prerequisites and setup requirements
- Verification checkpoints
- Troubleshooting sections
- Complexity levels (beginner/intermediate/advanced)

Usage:
    # From test examples JSON
    skill-seekers build-how-to-guides --input test_examples.json

    # From directory (auto-extracts workflows)
    skill-seekers build-how-to-guides tests/

    # With AI enhancement
    skill-seekers build-how-to-guides tests/ --enhance-with-ai

Example workflow → guide transformation:
    Input:  Multi-step test showing user registration + login + session
    Output: "How To: Complete User Authentication" guide with:
            - 5 discrete steps with explanations
            - Prerequisites (database, email service)
            - Verification points at each step
            - Common pitfalls and troubleshooting
            - Related guides suggestions
"""

import ast
import hashlib
import json
import logging
import re
from collections import defaultdict
from dataclasses import asdict, dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Literal

logger = logging.getLogger(__name__)


# ============================================================================
# DATA MODELS
# ============================================================================


@dataclass
class PrerequisiteItem:
    """Enhanced prerequisite with explanation (AI enhancement)"""

    name: str
    why: str  # Why this is needed
    setup: str  # How to install/configure


@dataclass
class TroubleshootingItem:
    """Enhanced troubleshooting with solutions (AI enhancement)"""

    problem: str
    symptoms: list[str] = field(default_factory=list)  # How to recognize this issue
    solution: str = ""  # Step-by-step fix
    diagnostic_steps: list[str] = field(default_factory=list)  # How to diagnose


@dataclass
class WorkflowStep:
    """Single step in a workflow guide"""

    step_number: int
    code: str
    description: str
    expected_result: str | None = None
    verification: str | None = None  # Assertion or checkpoint
    setup_required: str | None = None
    explanation: str | None = None  # Why this step matters
    common_pitfall: str | None = None  # Warning for this step
    common_variations: list[str] = field(default_factory=list)  # AI: Alternative approaches


@dataclass
class HowToGuide:
    """Complete how-to guide generated from workflow(s)"""

    guide_id: str
    title: str
    overview: str
    complexity_level: Literal["beginner", "intermediate", "advanced"]

    # Prerequisites
    prerequisites: list[str] = field(default_factory=list)
    required_imports: list[str] = field(default_factory=list)
    required_fixtures: list[str] = field(default_factory=list)

    # Content
    workflows: list[dict] = field(default_factory=list)  # Source workflow examples
    steps: list[WorkflowStep] = field(default_factory=list)

    # Metadata
    use_case: str = ""
    tags: list[str] = field(default_factory=list)
    estimated_time: str = "10 minutes"
    source_files: list[str] = field(default_factory=list)
    language: str = "python"  # Source file language

    # Optional AI enhancement (basic)
    common_pitfalls: list[str] = field(default_factory=list)
    troubleshooting: dict[str, str] = field(default_factory=dict)
    variations: list[str] = field(default_factory=list)
    related_guides: list[str] = field(default_factory=list)

    # AI enhancement (comprehensive - NEW)
    prerequisites_detailed: list[PrerequisiteItem] = field(default_factory=list)
    troubleshooting_detailed: list[TroubleshootingItem] = field(default_factory=list)
    next_steps_detailed: list[str] = field(default_factory=list)
    use_cases: list[str] = field(default_factory=list)

    def to_dict(self) -> dict:
        """Convert to dictionary"""
        result = asdict(self)
        # Convert WorkflowStep objects to dicts
        result["steps"] = [asdict(step) for step in self.steps]
        return result


@dataclass
class GuideCollection:
    """Collection of guides organized by category"""

    total_guides: int
    guides_by_complexity: dict[str, int]
    guides_by_use_case: dict[str, list[HowToGuide]]
    guides: list[HowToGuide]

    def to_dict(self) -> dict:
        """Convert to dictionary"""
        return {
            "total_guides": self.total_guides,
            "guides_by_complexity": self.guides_by_complexity,
            "guides_by_use_case": {
                k: [g.to_dict() for g in v] for k, v in self.guides_by_use_case.items()
            },
            "guides": [g.to_dict() for g in self.guides],
        }


# ============================================================================
# WORKFLOW ANALYZER
# ============================================================================


class WorkflowAnalyzer:
    """Analyze workflow examples to extract steps and metadata"""

    def analyze_workflow(self, workflow: dict) -> tuple[list[WorkflowStep], dict]:
        """
        Deep analysis of workflow structure.

        Args:
            workflow: TestExample dict from C3.2

        Returns:
            (steps, metadata) where metadata includes prerequisites, complexity, etc.
        """
        code = workflow.get("code", "")
        language = workflow.get("language", "python").lower()

        # Extract steps based on language
        if language == "python":
            steps = self._extract_steps_python(code, workflow)
        else:
            steps = self._extract_steps_heuristic(code, workflow)

        # Detect prerequisites
        metadata = self._detect_prerequisites(workflow)

        # NOTE: do NOT positionally re-associate verifications here.
        # _extract_steps_python already pairs each step with the assertion that
        # immediately follows it. `_find_verification_points(code)` returns ALL
        # assert lines in document order — a different-length/order list — so
        # `verifications[i]` attached the wrong (or a duplicate) check to a step.
        # The heuristic (non-Python) path simply has no per-step verification.

        # Calculate complexity
        metadata["complexity_level"] = self._calculate_complexity(steps, workflow)
        metadata["estimated_time"] = self._estimate_time(steps)

        return steps, metadata

    @classmethod
    def _iter_step_statements(cls, body: list[ast.stmt]):
        """Yield step statements in source order.

        Descends into control-flow blocks (with/for/while/if/try) so a test
        whose body is wrapped in e.g. ``with open(...):`` still yields steps,
        but — unlike ast.walk() — preserves document order and never enters
        nested function/class definitions (their bodies aren't workflow steps).
        """
        for node in body:
            if isinstance(node, (ast.Assign, ast.Expr, ast.Assert)):
                yield node
            elif isinstance(
                node, (ast.With, ast.AsyncWith, ast.For, ast.AsyncFor, ast.While, ast.If, ast.Try)
            ):
                yield from cls._iter_step_statements(getattr(node, "body", []))
                for handler in getattr(node, "handlers", []):
                    yield from cls._iter_step_statements(handler.body)
                yield from cls._iter_step_statements(getattr(node, "orelse", []))
                yield from cls._iter_step_statements(getattr(node, "finalbody", []))

    def _extract_steps_python(self, code: str, workflow: dict) -> list[WorkflowStep]:
        """Extract steps from Python code using AST"""
        steps = []

        try:
            tree = ast.parse(code)

            # Steps live at the top level of the test-function wrapper (the
            # common case); descend ONE level into it, else use the module body.
            body = tree.body
            if len(body) == 1 and isinstance(body[0], (ast.FunctionDef, ast.AsyncFunctionDef)):
                body = body[0].body
            statements = list(self._iter_step_statements(body))

            step_num = 1
            for idx, stmt in enumerate(statements):
                # Skip assertions for now (they're verifications)
                if isinstance(stmt, ast.Assert):
                    continue

                # Get code for this statement
                step_code = ast.get_source_segment(code, stmt)
                if not step_code:
                    continue

                # Generate description from code
                description = self._generate_step_description(stmt, step_code)

                # Check if next statement is assertion (verification)
                verification = None
                if idx + 1 < len(statements) and isinstance(statements[idx + 1], ast.Assert):
                    verification = ast.get_source_segment(code, statements[idx + 1])

                steps.append(
                    WorkflowStep(
                        step_number=step_num,
                        code=step_code,
                        description=description,
                        verification=verification,
                    )
                )
                step_num += 1

        except SyntaxError:
            # Fall back to heuristic method
            return self._extract_steps_heuristic(code, workflow)

        # Valid Python that yields no AST steps (e.g. only nested defs or bare
        # control flow) still deserves a guide — fall back to the line-based
        # heuristic rather than emitting an empty step list.
        if not steps:
            return self._extract_steps_heuristic(code, workflow)

        return steps

    def _extract_steps_heuristic(self, code: str, _workflow: dict) -> list[WorkflowStep]:
        """Extract steps using heuristics (for non-Python or invalid syntax)"""
        steps = []
        lines = code.split("\n")

        current_step = []
        step_num = 1

        for line in lines:
            line_stripped = line.strip()

            # Skip empty lines and comments
            if not line_stripped or line_stripped.startswith("#"):
                if current_step:
                    # End of current step
                    step_code = "\n".join(current_step)
                    description = self._infer_description_from_code(step_code)

                    steps.append(
                        WorkflowStep(
                            step_number=step_num,
                            code=step_code,
                            description=description,
                        )
                    )
                    step_num += 1
                    current_step = []
                continue

            current_step.append(line)

        # Add final step
        if current_step:
            step_code = "\n".join(current_step)
            description = self._infer_description_from_code(step_code)
            steps.append(
                WorkflowStep(step_number=step_num, code=step_code, description=description)
            )

        return steps

    def _generate_step_description(self, node: ast.AST, code: str) -> str:
        """Generate human-readable description from AST node"""
        if isinstance(node, ast.Assign):
            targets = [self._get_name(t) for t in node.targets]
            value_desc = self._describe_value(node.value)
            return f"Assign {', '.join(targets)} = {value_desc}"

        elif isinstance(node, ast.Expr):
            if isinstance(node.value, ast.Call):
                func_name = self._get_name(node.value.func)
                return f"Call {func_name}()"

        return code.split("\n")[0]  # First line as fallback

    def _describe_value(self, node: ast.AST) -> str:
        """Describe AST value node"""
        if isinstance(node, ast.Call):
            func_name = self._get_name(node.func)
            return f"{func_name}(...)"
        elif isinstance(node, ast.Constant):
            return repr(node.value)
        elif isinstance(node, ast.Name):
            return node.id
        return "value"

    def _get_name(self, node: ast.AST) -> str:
        """Extract name from AST node"""
        if isinstance(node, ast.Name):
            return node.id
        elif isinstance(node, ast.Attribute):
            return f"{self._get_name(node.value)}.{node.attr}"
        elif isinstance(node, ast.Call):
            return self._get_name(node.func)
        return "unknown"

    def _infer_description_from_code(self, code: str) -> str:
        """Infer description from code using patterns"""
        code = code.strip()

        # Method call patterns
        if "(" in code and ")" in code:
            match = re.search(r"(\w+)\s*\(", code)
            if match:
                return f"Call {match.group(1)}()"

        # Assignment patterns
        if "=" in code and not code.startswith("assert"):
            parts = code.split("=", 1)
            var_name = parts[0].strip()
            return f"Create {var_name}"

        # Assertion patterns
        if code.startswith("assert"):
            return "Verify result"

        return code.split("\n")[0]  # First line

    def _detect_prerequisites(self, workflow: dict) -> dict:
        """Detect prerequisites from workflow"""
        metadata = {
            "prerequisites": [],
            "required_imports": [],
            "required_fixtures": [],
        }

        # Get dependencies from workflow
        dependencies = workflow.get("dependencies", [])
        metadata["required_imports"] = dependencies

        # Get setup code
        setup_code = workflow.get("setup_code")
        if setup_code:
            metadata["prerequisites"].append("Setup code must be executed first")

        # Check for common fixtures in test name or setup
        test_name = workflow.get("test_name", "").lower()
        if "database" in test_name or (setup_code and "database" in setup_code.lower()):
            metadata["required_fixtures"].append("database")
        if "api" in test_name or (setup_code and "api" in setup_code.lower()):
            metadata["required_fixtures"].append("api_client")

        return metadata

    def _find_verification_points(self, code: str) -> list[str]:
        """Find assertion statements in code"""
        verifications = []

        for line in code.split("\n"):
            line_stripped = line.strip()
            if line_stripped.startswith("assert"):
                verifications.append(line_stripped)

        return verifications

    def _calculate_complexity(self, steps: list[WorkflowStep], workflow: dict) -> str:
        """Calculate complexity level"""
        num_steps = len(steps)

        # Check for advanced patterns
        code = workflow.get("code", "")
        has_async = "async" in code or "await" in code
        has_mock = "mock" in code.lower() or "patch" in code.lower()
        has_error_handling = "try" in code or "except" in code

        _complexity_score = workflow.get("complexity_score", 0.5)

        # Determine level
        if num_steps <= 3 and not has_async and not has_mock:
            return "beginner"
        elif num_steps >= 8 or has_async or has_error_handling:
            return "advanced"
        else:
            return "intermediate"

    def _estimate_time(self, steps: list[WorkflowStep]) -> str:
        """Estimate time to complete guide"""
        num_steps = len(steps)

        if num_steps <= 3:
            return "5 minutes"
        elif num_steps <= 6:
            return "10 minutes"
        elif num_steps <= 10:
            return "15 minutes"
        else:
            return "20 minutes"


# ============================================================================
# WORKFLOW GROUPER
# ============================================================================


class WorkflowGrouper:
    """Group related workflows into coherent guides"""

    def group_workflows(
        self, workflows: list[dict], strategy: str = "ai-tutorial-group"
    ) -> dict[str, list[dict]]:
        """
        Group workflows using specified strategy.

        Args:
            workflows: List of workflow examples
            strategy: "ai-tutorial-group", "file-path", "test-name", "complexity"

        Returns:
            Dict mapping group name to list of workflows
        """
        if strategy == "ai-tutorial-group":
            return self._group_by_ai_tutorial_group(workflows)
        elif strategy == "file-path":
            return self._group_by_file_path(workflows)
        elif strategy == "test-name":
            return self._group_by_test_name(workflows)
        elif strategy == "complexity":
            return self._group_by_complexity(workflows)
        else:
            # Default: AI tutorial group with fallback
            groups = self._group_by_ai_tutorial_group(workflows)
            if not groups or len(groups) == len(workflows):
                # Fallback to file path if AI grouping didn't work well
                groups = self._group_by_file_path(workflows)
            return groups

    def _group_by_ai_tutorial_group(self, workflows: list[dict]) -> dict[str, list[dict]]:
        """Group by AI-generated tutorial_group (from C3.6 enhancement)"""
        groups = defaultdict(list)
        ungrouped = []

        for workflow in workflows:
            ai_analysis = workflow.get("ai_analysis") or {}
            tutorial_group = ai_analysis.get("tutorial_group")

            if tutorial_group:
                groups[tutorial_group].append(workflow)
            else:
                ungrouped.append(workflow)

        # Put ungrouped workflows in individual guides
        for workflow in ungrouped:
            test_name = workflow.get("test_name", "Unknown")
            # Clean test name for title
            title = self._clean_test_name(test_name)
            groups[title] = [workflow]

        return dict(groups)

    def _group_by_file_path(self, workflows: list[dict]) -> dict[str, list[dict]]:
        """Group workflows from same test file"""
        groups = defaultdict(list)

        for workflow in workflows:
            file_path = workflow.get("file_path", "")
            # Extract meaningful name from file path
            file_name = Path(file_path).stem if file_path else "Unknown"
            # Remove test_ prefix
            group_name = file_name.replace("test_", "").replace("_", " ").title()
            groups[group_name].append(workflow)

        return dict(groups)

    def _group_by_test_name(self, workflows: list[dict]) -> dict[str, list[dict]]:
        """Group by common test name prefixes"""
        groups = defaultdict(list)

        for workflow in workflows:
            test_name = workflow.get("test_name", "")
            # Extract prefix (e.g., test_auth_login → auth)
            prefix = self._extract_prefix(test_name)
            groups[prefix].append(workflow)

        return dict(groups)

    def _group_by_complexity(self, workflows: list[dict]) -> dict[str, list[dict]]:
        """Group by complexity level"""
        groups = {"Beginner": [], "Intermediate": [], "Advanced": []}

        for workflow in workflows:
            complexity_score = workflow.get("complexity_score", 0.5)

            if complexity_score < 0.4:
                groups["Beginner"].append(workflow)
            elif complexity_score < 0.7:
                groups["Intermediate"].append(workflow)
            else:
                groups["Advanced"].append(workflow)

        # Remove empty groups
        return {k: v for k, v in groups.items() if v}

    def _clean_test_name(self, test_name: str) -> str:
        """Clean test name to readable title"""
        # Remove test_ prefix
        name = test_name.replace("test_", "")
        # Replace underscores with spaces
        name = name.replace("_", " ")
        # Title case
        return name.title()

    def _extract_prefix(self, test_name: str) -> str:
        """Extract prefix from test name"""
        # Remove test_ prefix
        name = test_name.replace("test_", "")
        # Get first part before underscore
        parts = name.split("_")
        if len(parts) > 1:
            return parts[0].title()
        return self._clean_test_name(test_name)


# ============================================================================
# GUIDE GENERATOR
# ============================================================================


class GuideGenerator:
    """Generate markdown guides from workflow data"""

    def generate_guide_markdown(self, guide: HowToGuide) -> str:
        """
        Generate complete markdown guide.

        Args:
            guide: HowToGuide object with all data

        Returns:
            Complete markdown string
        """
        sections = []

        # Header
        sections.append(self._create_header(guide))

        # Overview
        sections.append(self._create_overview(guide))

        # Prerequisites
        if guide.prerequisites or guide.required_imports or guide.required_fixtures:
            sections.append(self._create_prerequisites(guide))

        # Step-by-step guide
        sections.append(self._create_steps_section(guide.steps, guide.language))

        # Complete example
        sections.append(self._create_complete_example(guide))

        # Troubleshooting (if available)
        if guide.common_pitfalls or guide.troubleshooting:
            sections.append(self._create_troubleshooting(guide))

        # Next steps and related guides
        sections.append(self._create_next_steps(guide))

        # Footer
        sections.append(self._create_footer(guide))

        return "\n\n".join(sections)

    def _create_header(self, guide: HowToGuide) -> str:
        """Create guide header with metadata"""
        lines = [f"# How To: {guide.title}"]
        lines.append("")
        lines.append(f"**Difficulty**: {guide.complexity_level.title()}")
        lines.append(f"**Estimated Time**: {guide.estimated_time}")

        if guide.tags:
            lines.append(f"**Tags**: {', '.join(guide.tags)}")

        return "\n".join(lines)

    def _create_overview(self, guide: HowToGuide) -> str:
        """Create overview section"""
        return f"## Overview\n\n{guide.overview}"

    def _create_prerequisites(self, guide: HowToGuide) -> str:
        """Create prerequisites section"""
        lines = ["## Prerequisites"]
        lines.append("")

        # Checklist format
        if guide.prerequisites:
            for prereq in guide.prerequisites:
                lines.append(f"- [ ] {prereq}")
            lines.append("")

        # Required imports
        if guide.required_imports:
            lines.append("**Required Modules:**")
            for imp in guide.required_imports:
                lines.append(f"- `{imp}`")
            lines.append("")

        # Required fixtures
        if guide.required_fixtures:
            lines.append("**Required Fixtures:**")
            for fixture in guide.required_fixtures:
                lines.append(f"- `{fixture}` fixture")
            lines.append("")

        # Setup code if available
        if guide.workflows and guide.workflows[0].get("setup_code"):
            setup_code = guide.workflows[0]["setup_code"]
            lines.append("**Setup Required:**")
            lines.append(f"```{guide.language}")
            lines.append(setup_code)
            lines.append("```")

        return "\n".join(lines)

    def _create_steps_section(self, steps: list[WorkflowStep], language: str = "python") -> str:
        """Create step-by-step guide section"""
        lines = ["## Step-by-Step Guide"]
        lines.append("")

        for step in steps:
            lines.append(f"### Step {step.step_number}: {step.description}")
            lines.append("")

            # Explanation if available
            if step.explanation:
                lines.append(f"**What you're doing:** {step.explanation}")
                lines.append("")

            # Code
            lines.append(f"```{language}")
            lines.append(step.code)
            lines.append("```")
            lines.append("")

            # Expected result
            if step.expected_result:
                lines.append(f"**Expected Result:** {step.expected_result}")
                lines.append("")

            # Verification checkpoint
            if step.verification:
                lines.append("**Verification:**")
                lines.append(f"```{language}")
                lines.append(step.verification)
                lines.append("```")
                lines.append("")

            # Common pitfall warning
            if step.common_pitfall:
                lines.append(f"⚠️ **Common Pitfall:** {step.common_pitfall}")
                lines.append("")

        return "\n".join(lines)

    def _create_complete_example(self, guide: HowToGuide) -> str:
        """Create complete working example"""
        lines = ["## Complete Example"]
        lines.append("")
        lines.append(f"```{guide.language}")

        # If we have workflows, use the first one's code
        if guide.workflows:
            workflow = guide.workflows[0]

            # Add setup code if present
            if workflow.get("setup_code"):
                lines.append("# Setup")
                lines.append(workflow["setup_code"])
                lines.append("")

            # Add main workflow code
            lines.append("# Workflow")
            lines.append(workflow.get("code", ""))
        else:
            # Combine all steps
            for step in guide.steps:
                lines.append(f"# Step {step.step_number}: {step.description}")
                lines.append(step.code)
                if step.verification:
                    lines.append(step.verification)
                lines.append("")

        lines.append("```")
        return "\n".join(lines)

    def _create_troubleshooting(self, guide: HowToGuide) -> str:
        """Create troubleshooting section"""
        lines = ["## Troubleshooting"]
        lines.append("")

        # Common pitfalls
        if guide.common_pitfalls:
            lines.append("### Common Issues")
            lines.append("")
            for i, pitfall in enumerate(guide.common_pitfalls, 1):
                lines.append(f"{i}. {pitfall}")
            lines.append("")

        # Specific troubleshooting
        if guide.troubleshooting:
            for problem, solution in guide.troubleshooting.items():
                lines.append(f"### Problem: {problem}")
                lines.append("")
                lines.append(f"**Solution:** {solution}")
                lines.append("")

        return "\n".join(lines)

    def _create_next_steps(self, guide: HowToGuide) -> str:
        """Create next steps and related guides"""
        lines = ["## Next Steps"]
        lines.append("")

        # Variations if available
        if guide.variations:
            lines.append("**Try these variations:**")
            for variation in guide.variations:
                lines.append(f"- {variation}")
            lines.append("")

        # Related guides
        if guide.related_guides:
            lines.append("## Related Guides")
            lines.append("")
            for related in guide.related_guides:
                lines.append(f"- [{related}]")
            lines.append("")

        return "\n".join(lines)

    def _create_footer(self, guide: HowToGuide) -> str:
        """Create guide footer with metadata"""
        source_info = []
        if guide.source_files:
            source_info.append(f"Source: {', '.join(guide.source_files)}")
        source_info.append(f"Complexity: {guide.complexity_level.title()}")
        source_info.append(f"Last updated: {datetime.now().strftime('%Y-%m-%d')}")

        return f"---\n\n*{' | '.join(source_info)}*"

    def generate_index(self, guides: list[HowToGuide]) -> str:
        """
        Generate index/TOC markdown.

        Args:
            guides: List of all guides

        Returns:
            Index markdown string
        """
        lines = ["# How-To Guides Index"]
        lines.append("")
        lines.append(f"**Total Guides**: {len(guides)}")
        lines.append(f"**Last Updated**: {datetime.now().strftime('%Y-%m-%d')}")
        lines.append("")

        # Group by use case
        by_use_case = defaultdict(list)
        for guide in guides:
            use_case = guide.use_case or "Other"
            by_use_case[use_case].append(guide)

        lines.append("## By Use Case")
        lines.append("")

        for use_case in sorted(by_use_case.keys()):
            case_guides = by_use_case[use_case]
            lines.append(f"### {use_case} ({len(case_guides)} guides)")
            _difficulty_rank = {"beginner": 0, "intermediate": 1, "advanced": 2}
            for guide in sorted(
                case_guides, key=lambda g: _difficulty_rank.get(g.complexity_level, 1)
            ):
                # Create filename from guide title
                filename = guide.title.lower().replace(" ", "-").replace(":", "")
                lines.append(
                    f"- [How To: {guide.title}]({use_case.lower()}/{filename}.md) - {guide.complexity_level.title()}"
                )
            lines.append("")

        # Group by difficulty
        by_complexity = defaultdict(list)
        for guide in guides:
            by_complexity[guide.complexity_level].append(guide)

        lines.append("## By Difficulty Level")
        lines.append("")

        for level in ["beginner", "intermediate", "advanced"]:
            if level in by_complexity:
                level_guides = by_complexity[level]
                lines.append(f"### {level.title()} ({len(level_guides)} guides)")
                for guide in sorted(level_guides, key=lambda g: g.title):
                    lines.append(f"- {guide.title}")
                lines.append("")

        return "\n".join(lines)


# ============================================================================
# HOW-TO GUIDE BUILDER (Main Orchestrator)
# ============================================================================


class HowToGuideBuilder:
    """Main orchestrator for building how-to guides from workflow examples"""

    def __init__(self, enhance_with_ai: bool = True):
        """
        Initialize guide builder.

        Args:
            enhance_with_ai: Enable AI enhancement (requires C3.6 AI analysis in workflows)
        """
        self.enhance_with_ai = enhance_with_ai
        self.analyzer = WorkflowAnalyzer()
        self.grouper = WorkflowGrouper()
        self.generator = GuideGenerator()

    def build_guides_from_examples(
        self,
        examples: list[dict],
        grouping_strategy: str = "ai-tutorial-group",
        output_dir: Path | None = None,
        enhance_with_ai: bool = True,
        ai_mode: str = "auto",
    ) -> GuideCollection:
        """
        Main entry point - build guides from workflow examples.

        Args:
            examples: List of TestExample dicts from C3.2
            grouping_strategy: How to group workflows ("ai-tutorial-group", "file-path", etc.)
            output_dir: Optional directory to save markdown files
            enhance_with_ai: Enable comprehensive AI enhancement (default: True)
            ai_mode: AI enhancement mode - "auto", "api", "local", or "none"

        Returns:
            GuideCollection with all generated guides
        """
        logger.info(f"Building how-to guides from {len(examples)} examples...")

        # Initialize AI enhancer if requested
        enhancer = None
        if enhance_with_ai and ai_mode != "none":
            try:
                from .guide_enhancer import GuideEnhancer

                enhancer = GuideEnhancer(mode=ai_mode)
                logger.info(f"✨ AI enhancement enabled (mode: {enhancer.mode})")
            except Exception as e:
                logger.warning(f"⚠️  AI enhancement unavailable: {e}")
                logger.info("📝 Falling back to basic guide generation")

        # Filter to workflow examples only
        workflows = self._extract_workflow_examples(examples)
        logger.info(f"Found {len(workflows)} workflow examples (from {len(examples)} total)")

        if not workflows:
            # Log categories for debugging
            categories = {ex.get("category", "unknown") for ex in examples}
            logger.warning(f"No workflow examples found! Categories in input: {categories}")
            logger.info(
                "Tip: Workflow detection requires keywords like 'workflow', 'integration', 'e2e' in test names,"
            )
            logger.info("     or tests with 4+ assignments and 3+ method calls")
            return GuideCollection(
                total_guides=0,
                guides_by_complexity={},
                guides_by_use_case={},
                guides=[],
            )

        # Group workflows
        grouped_workflows = self.grouper.group_workflows(workflows, grouping_strategy)
        logger.info(f"Grouped into {len(grouped_workflows)} guide categories")

        # Build guides
        guides = []
        for title, workflow_group in grouped_workflows.items():
            guide = self._create_guide(title, workflow_group, enhancer)
            guides.append(guide)

        # Create collection
        collection = self._create_collection(guides)

        # Save to files if output directory provided
        if output_dir:
            self._save_guides_to_files(collection, output_dir)

        logger.info(f"✅ Generated {len(guides)} how-to guides")
        return collection

    def _extract_workflow_examples(self, examples: list[dict]) -> list[dict]:
        """Filter to examples suitable for guide generation.

        Includes:
        - All workflow-category examples
        - Setup/config examples with sufficient complexity (4+ steps or high confidence)
        - Instantiation examples with high confidence and multiple dependencies
        """
        guide_worthy = []
        for ex in examples:
            if not isinstance(ex, dict):
                continue
            category = ex.get("category", "")
            complexity = ex.get("complexity_score", 0)
            confidence = ex.get("confidence", 0)

            if category == "workflow":
                guide_worthy.append(ex)
            elif category in ("setup", "config") and (complexity >= 0.4 or confidence >= 0.7):
                guide_worthy.append(ex)
            elif category == "instantiation" and complexity >= 0.6 and confidence >= 0.7:
                guide_worthy.append(ex)

        return guide_worthy

    def _create_guide(self, title: str, workflows: list[dict], enhancer=None) -> HowToGuide:
        """
        Generate single guide from workflow(s).

        Args:
            title: Guide title
            workflows: List of related workflow examples
            enhancer: Optional GuideEnhancer instance for AI enhancement

        Returns:
            Complete HowToGuide object
        """
        # Use first workflow as primary
        primary_workflow = workflows[0]

        # Analyze workflow to extract steps
        steps, metadata = self.analyzer.analyze_workflow(primary_workflow)

        # Generate guide ID
        guide_id = hashlib.md5(title.encode()).hexdigest()[:12]

        # Extract use case from AI analysis or title
        use_case = title

        ai_analysis = primary_workflow.get("ai_analysis") or {}
        if ai_analysis:
            use_case = ai_analysis.get("tutorial_group", title)

        # Determine overview
        overview = self._generate_overview(primary_workflow, workflows)

        # Extract tags
        tags = primary_workflow.get("tags", [])

        # Extract source files
        source_files = [w.get("file_path", "") for w in workflows]
        source_files = [
            f"{Path(f).name}:{w.get('line_start', 0)}"
            for f, w in zip(source_files, workflows, strict=False)
        ]

        # Create guide
        guide = HowToGuide(
            guide_id=guide_id,
            title=title,
            overview=overview,
            complexity_level=metadata.get("complexity_level", "intermediate"),
            prerequisites=metadata.get("prerequisites", []),
            required_imports=metadata.get("required_imports", []),
            required_fixtures=metadata.get("required_fixtures", []),
            workflows=workflows,
            steps=steps,
            use_case=use_case,
            tags=tags,
            estimated_time=metadata.get("estimated_time", "10 minutes"),
            source_files=source_files,
            language=primary_workflow.get("language", "python"),
        )

        # Add AI enhancements if enhancer is available
        ai_analysis_for_enhancement = primary_workflow.get("ai_analysis") or {}
        if enhancer:
            self._enhance_guide_with_ai(guide, ai_analysis_for_enhancement, enhancer)
        elif self.enhance_with_ai and ai_analysis_for_enhancement:
            # Fallback to old enhancement method (basic)
            self._enhance_guide_with_ai_basic(guide, ai_analysis_for_enhancement)

        return guide

    def _generate_overview(self, primary_workflow: dict, _all_workflows: list[dict]) -> str:
        """Generate guide overview"""
        # Try to get explanation from AI analysis

        ai_analysis = primary_workflow.get("ai_analysis") or {}
        if ai_analysis:
            explanation = ai_analysis.get("explanation")
            if explanation:
                return explanation

        # Fallback to description
        description = primary_workflow.get("description", "")
        if description:
            return description

        # Final fallback
        return f"Learn how to use {primary_workflow.get('test_name', 'this feature')} in your code."

    def _enhance_guide_with_ai(self, guide: HowToGuide, _ai_analysis: dict, enhancer):
        """
        Comprehensively enhance guide with AI using GuideEnhancer.

        Applies all 5 enhancements:
        1. Step descriptions - Natural language explanations        2. Troubleshooting - Diagnostic flows + solutions
        3. Prerequisites - Why needed + setup
        4. Next steps - Related guides, variations
        5. Use cases - Real-world scenarios

        Args:
            guide: HowToGuide object to enhance
            ai_analysis: AI analysis data from C3.6 (for context)
            enhancer: GuideEnhancer instance
        """
        # Prepare guide data for enhancer
        guide_data = {
            "title": guide.title,
            "steps": [{"description": step.description, "code": step.code} for step in guide.steps],
            "language": guide.language,
            "prerequisites": guide.prerequisites,
            "description": guide.overview,
        }

        # Call enhancer to get all 5 enhancements
        enhanced_data = enhancer.enhance_guide(guide_data)

        # Apply step enhancements
        if "step_enhancements" in enhanced_data:
            for enhancement in enhanced_data["step_enhancements"]:
                idx = enhancement.step_index
                if 0 <= idx < len(guide.steps):
                    guide.steps[idx].explanation = enhancement.explanation
                    guide.steps[idx].common_variations = enhancement.variations

        # Apply detailed prerequisites
        if "prerequisites_detailed" in enhanced_data:
            guide.prerequisites_detailed = enhanced_data["prerequisites_detailed"]

        # Apply troubleshooting
        if "troubleshooting_detailed" in enhanced_data:
            guide.troubleshooting_detailed = enhanced_data["troubleshooting_detailed"]

        # Apply next steps
        if "next_steps_detailed" in enhanced_data:
            guide.next_steps_detailed = enhanced_data["next_steps_detailed"]

        # Apply use cases
        if "use_cases" in enhanced_data:
            guide.use_cases = enhanced_data["use_cases"]

        logger.info(f"✨ Enhanced guide '{guide.title}' with comprehensive AI improvements")

    def _enhance_guide_with_ai_basic(self, guide: HowToGuide, ai_analysis: dict):
        """
        Basic enhancement using pre-computed AI analysis from C3.6.

        This is a fallback when GuideEnhancer is not available.

        Args:
            guide: HowToGuide object to enhance
            ai_analysis: AI analysis data from C3.6
        """
        # Add best practices as variations
        best_practices = ai_analysis.get("best_practices", [])
        guide.variations = best_practices

        # Add common mistakes as pitfalls
        common_mistakes = ai_analysis.get("common_mistakes", [])
        guide.common_pitfalls = common_mistakes

        # Add related examples as related guides
        related_examples = ai_analysis.get("related_examples", [])
        guide.related_guides = [f"How To: {ex}" for ex in related_examples]

        # NOTE: best_practices are general guidance, not per-step explanations —
        # they're surfaced via guide.variations above. Previously they were also
        # mapped onto step explanations positionally (step N -> best_practice[N]),
        # which overwrote real step explanations with unrelated strings.

    def _create_collection(self, guides: list[HowToGuide]) -> GuideCollection:
        """Create GuideCollection from guides"""
        # Count by complexity
        by_complexity = defaultdict(int)
        for guide in guides:
            by_complexity[guide.complexity_level] += 1

        # Group by use case
        by_use_case = defaultdict(list)
        for guide in guides:
            use_case = guide.use_case or "Other"
            by_use_case[use_case].append(guide)

        return GuideCollection(
            total_guides=len(guides),
            guides_by_complexity=dict(by_complexity),
            guides_by_use_case=dict(by_use_case),
            guides=guides,
        )

    def _save_guides_to_files(self, collection: GuideCollection, output_dir: Path):
        """Save guides to markdown files"""
        output_dir = Path(output_dir)
        output_dir.mkdir(parents=True, exist_ok=True)

        logger.info(f"Saving guides to {output_dir}...")

        # Save individual guides
        for use_case, guides in collection.guides_by_use_case.items():
            # Create use case directory
            use_case_dir = output_dir / use_case.lower().replace(" ", "-")
            use_case_dir.mkdir(parents=True, exist_ok=True)

            for guide in guides:
                # Generate filename from title
                filename = guide.title.lower().replace(" ", "-").replace(":", "") + ".md"
                file_path = use_case_dir / filename

                # Generate and save markdown
                markdown = self.generator.generate_guide_markdown(guide)
                file_path.write_text(markdown, encoding="utf-8")

        # Save index
        index_markdown = self.generator.generate_index(collection.guides)
        (output_dir / "index.md").write_text(index_markdown, encoding="utf-8")

        logger.info(f"✅ Saved {collection.total_guides} guides + index to {output_dir}")


# ============================================================================
# CLI INTERFACE
# ============================================================================


def main():
    """CLI entry point for how-to guide builder"""
    import argparse
    import sys

    parser = argparse.ArgumentParser(
        description="Build how-to guides from workflow test examples (C3.3)",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # From test examples JSON (C3.2 output)
  skill-seekers build-how-to-guides --input test_examples.json

  # From directory (extracts workflows)
  skill-seekers build-how-to-guides tests/

  # Custom grouping strategy
  skill-seekers build-how-to-guides tests/ --group-by file-path

  # Custom output directory
  skill-seekers build-how-to-guides tests/ --output tutorials/

  # Without AI enhancement
  skill-seekers build-how-to-guides tests/ --no-ai

Grouping Strategies:
  - ai-tutorial-group: Use AI-generated tutorial groups (default, best)
  - file-path: Group by source test file
  - test-name: Group by test name patterns
  - complexity: Group by difficulty level
""",
    )

    parser.add_argument(
        "input",
        nargs="?",
        help="Input: directory with test files OR test_examples.json file",
    )

    parser.add_argument(
        "--input",
        dest="input_file",
        help="Input JSON file with test examples (from C3.2)",
    )

    parser.add_argument(
        "--output",
        default="output/codebase/tutorials",
        help="Output directory for generated guides (default: output/codebase/tutorials)",
    )

    parser.add_argument(
        "--group-by",
        choices=["ai-tutorial-group", "file-path", "test-name", "complexity"],
        default="ai-tutorial-group",
        help="Grouping strategy (default: ai-tutorial-group)",
    )

    parser.add_argument("--no-ai", action="store_true", help="Disable AI enhancement")

    parser.add_argument(
        "--json-output",
        action="store_true",
        help="Output JSON summary instead of markdown files",
    )

    args = parser.parse_args()

    # Determine input source
    input_path = args.input or args.input_file

    if not input_path:
        parser.print_help()
        print("\n❌ Error: No input provided")
        print("   Provide either a directory or --input JSON file")
        sys.exit(1)

    input_path = Path(input_path)

    # Load examples
    examples = []

    if input_path.is_file() and input_path.suffix == ".json":
        # Load from JSON file
        logger.info(f"Loading examples from {input_path}...")
        with open(input_path) as f:
            data = json.load(f)
            if isinstance(data, dict) and "examples" in data:
                examples = data["examples"]
            elif isinstance(data, list):
                examples = data
            else:
                print(f"❌ Error: Invalid JSON format in {input_path}")
                sys.exit(1)

    elif input_path.is_dir():
        # Extract from directory using test example extractor
        print("⚠️  Directory input requires test example extractor")
        print("   Please use test_examples.json output from C3.2")
        print(f"   Or run: skill-seekers extract-test-examples {input_path} --json > examples.json")
        sys.exit(1)

    else:
        print(f"❌ Error: Input path not found: {input_path}")
        sys.exit(1)

    # Build guides
    builder = HowToGuideBuilder(enhance_with_ai=not args.no_ai)
    output_dir = Path(args.output) if not args.json_output else None

    collection = builder.build_guides_from_examples(
        examples, grouping_strategy=args.group_by, output_dir=output_dir
    )

    # Output results
    if args.json_output:
        # JSON output
        print(json.dumps(collection.to_dict(), indent=2))
    else:
        # Summary
        print()
        print("=" * 60)
        print("HOW-TO GUIDES GENERATED")
        print("=" * 60)
        print()
        print(f"Total Guides: {collection.total_guides}")
        print()
        print("By Complexity:")
        for level, count in collection.guides_by_complexity.items():
            print(f"  - {level.title()}: {count} guides")
        print()
        print("By Use Case:")
        for use_case, guides in collection.guides_by_use_case.items():
            print(f"  - {use_case}: {len(guides)} guides")
        print()
        if output_dir:
            print(f"📁 Output directory: {output_dir}")
            print(f"📄 Index file: {output_dir}/index.md")
            print()

    sys.exit(0)


if __name__ == "__main__":
    main()
