"""
Claude Generator — Uses the Claude API to write the CLAUDE.md file.

Takes all gathered codebase data and synthesizes a high-quality,
well-structured CLAUDE.md that stays within token limits.
"""

import os
from typing import Optional
import anthropic


GENERATION_SYSTEM_PROMPT = """You are an expert software architect helping developers configure AI coding assistants.

Your job is to write a CLAUDE.md file — the context document that an AI coding assistant reads to understand a codebase before helping with any task.

A great CLAUDE.md:
1. Is concise (under 2000 tokens / ~1500 words)
2. Covers the essentials: project purpose, architecture, conventions, key files, workflows
3. Tells the AI what NOT to do as clearly as what TO do
4. Uses clear headings and bullet points
5. Prioritizes information the AI needs on EVERY task vs. niche edge cases
6. Does NOT repeat information the AI can easily infer from reading files

CRITICAL: Be selective. A 500-word CLAUDE.md that covers the 20% of context that matters 80% of the time is far better than a 3000-word document that wastes the AI's context window on irrelevant details."""


UPDATE_SYSTEM_PROMPT = """You are an expert at maintaining CLAUDE.md files for AI coding assistants.

You will be given:
1. The current CLAUDE.md content
2. What has changed in the codebase since it was written
3. Specific sections that are now outdated

Your job: Update ONLY the sections that are stale. Do not rewrite sections that are still accurate.
Preserve any section marked with <!-- MANUAL --> exactly as-is.
Return the complete updated CLAUDE.md."""


class ClaudeGenerator:
    """Generates and updates CLAUDE.md using the Claude API."""

    def __init__(self, api_key: Optional[str] = None, model: str = "claude-haiku-4-5-20251001"):
        self.api_key = api_key or os.environ.get("ANTHROPIC_API_KEY", "")
        self.model = model
        self._client: Optional[anthropic.Anthropic] = None

    @property
    def client(self) -> anthropic.Anthropic:
        if not self._client:
            if not self.api_key:
                raise ValueError(
                    "No Anthropic API key. Set ANTHROPIC_API_KEY environment variable."
                )
            self._client = anthropic.Anthropic(api_key=self.api_key)
        return self._client

    def generate(
        self,
        stack_data: dict,
        scan_data: dict,
        git_data: dict,
        doc_data: dict,
        project_name: str = "",
        max_tokens: int = 2000,
    ) -> str:
        """
        Generate a complete CLAUDE.md from scratch.

        Args:
            stack_data: Technology stack information
            scan_data: Directory structure and file stats
            git_data: Git history and patterns
            doc_data: Documentation content
            project_name: Name of the project
            max_tokens: Maximum tokens to generate

        Returns:
            Generated CLAUDE.md content as a string.
        """
        context = self._build_generation_context(
            stack_data, scan_data, git_data, doc_data, project_name
        )

        prompt = f"""Generate a CLAUDE.md for this project.

{context}

Write a well-structured CLAUDE.md that covers:
1. Project overview (1-2 sentences on what it does)
2. Tech stack summary
3. Architecture/structure (key dirs and what they contain)
4. Key conventions and patterns used in this codebase
5. Important commands (build, test, run, deploy)
6. What NOT to do / gotchas / things to avoid
7. Key files to know about

Keep it under 1500 words. Use clear headers (##) and bullet points. Be specific to THIS codebase."""

        response = self.client.messages.create(
            model=self.model,
            max_tokens=max_tokens,
            system=GENERATION_SYSTEM_PROMPT,
            messages=[{"role": "user", "content": prompt}],
        )

        return response.content[0].text

    def update_section(
        self,
        current_content: str,
        section_name: str,
        change_description: str,
        codebase_context: str = "",
    ) -> str:
        """
        Update a specific section of an existing CLAUDE.md.

        Args:
            current_content: The full current CLAUDE.md content
            section_name: The section heading to update
            change_description: Description of what changed
            codebase_context: Additional codebase context

        Returns:
            Updated CLAUDE.md content.
        """
        prompt = f"""Update the "{section_name}" section of this CLAUDE.md:

CURRENT CLAUDE.MD:
{current_content}

WHAT CHANGED:
{change_description}

{f'ADDITIONAL CONTEXT: {codebase_context}' if codebase_context else ''}

Update the "{section_name}" section to reflect the changes.
Return the COMPLETE CLAUDE.md with only that section updated.
Leave all other sections exactly as they are.
Preserve any <!-- MANUAL --> comments and the content below them."""

        response = self.client.messages.create(
            model=self.model,
            max_tokens=3000,
            system=UPDATE_SYSTEM_PROMPT,
            messages=[{"role": "user", "content": prompt}],
        )

        return response.content[0].text

    def regenerate_stale_sections(
        self,
        current_content: str,
        stale_sections: list[dict],
        new_codebase_context: str,
    ) -> str:
        """
        Regenerate all stale sections at once.

        Args:
            current_content: Current CLAUDE.md
            stale_sections: List of dicts with 'section' and 'reason' keys
            new_codebase_context: Updated codebase info

        Returns:
            Updated CLAUDE.md.
        """
        stale_list = "\n".join(
            f"- {s['section']}: {s['reason']}" for s in stale_sections
        )

        prompt = f"""Update this CLAUDE.md. The following sections are outdated:

{stale_list}

CURRENT CLAUDE.MD:
{current_content}

CURRENT CODEBASE STATE:
{new_codebase_context}

Update ALL the stale sections. Leave accurate sections unchanged.
Return the complete updated CLAUDE.md."""

        response = self.client.messages.create(
            model=self.model,
            max_tokens=3000,
            system=UPDATE_SYSTEM_PROMPT,
            messages=[{"role": "user", "content": prompt}],
        )

        return response.content[0].text

    def _build_generation_context(
        self,
        stack_data: dict,
        scan_data: dict,
        git_data: dict,
        doc_data: dict,
        project_name: str,
    ) -> str:
        """Build the context string for the generation prompt."""
        parts = []

        # Project name
        name = project_name or scan_data.get("project_name", "Unknown")
        parts.append(f"PROJECT NAME: {name}\n")

        # README summary
        readme = doc_data.get("readme_summary", "")
        if readme:
            parts.append(f"README SUMMARY:\n{readme[:500]}\n")

        # Tech stack
        if stack_data:
            parts.append("TECHNOLOGY STACK:")
            for key in ["languages", "frameworks", "databases", "test_frameworks", "build_tools", "tools"]:
                values = stack_data.get(key, [])
                if values:
                    parts.append(f"  {key.replace('_', ' ').title()}: {', '.join(values)}")
            runtime = stack_data.get("runtime", {})
            if runtime:
                parts.append(f"  Runtime versions: {', '.join(f'{k} {v}' for k, v in runtime.items())}")
            parts.append("")

        # Directory structure
        tree = scan_data.get("tree", "")
        if tree:
            # Limit tree depth for context
            tree_lines = tree.split("\n")[:40]
            parts.append(f"DIRECTORY STRUCTURE:\n{chr(10).join(tree_lines)}\n")

        # File stats
        stats = scan_data.get("stats", {})
        if stats.get("total_code_files"):
            parts.append(f"CODE FILES: {stats['total_code_files']} total")

        # Key files
        key_files = scan_data.get("key_files", [])
        if key_files:
            parts.append(f"ENTRY POINTS: {', '.join(key_files[:6])}")

        # Config files found
        config_files = scan_data.get("config_files", [])
        if config_files:
            parts.append(f"CONFIG FILES: {', '.join(config_files[:8])}")

        parts.append("")

        # Git info
        if git_data.get("is_git_repo"):
            git_stats = git_data.get("commit_stats", {})
            branch_info = git_data.get("branch_info", {})
            parts.append(f"GIT: {git_stats.get('total_commits', '?')} commits, "
                        f"{len(git_stats.get('authors', []))} contributors, "
                        f"branch strategy: {branch_info.get('strategy', 'unknown')}")

            hot_spots = git_data.get("hot_spots", [])
            if hot_spots:
                hot_str = ", ".join(f"{f}" for f, _ in hot_spots[:5])
                parts.append(f"MOST CHANGED FILES: {hot_str}")

        parts.append("")

        # Make targets (reveal dev workflow)
        make_targets = doc_data.get("make_targets", [])
        if make_targets:
            parts.append(f"MAKE TARGETS: {', '.join(make_targets)}")

        # Existing docs
        docs = doc_data.get("docs", {})
        for doc_name, doc_content in docs.items():
            if doc_name not in ("README.md", "README.rst"):  # Already used above
                parts.append(f"\n{doc_name.upper()}:\n{doc_content[:800]}")

        # Existing CLAUDE.md if any (use as template/reference)
        existing = doc_data.get("existing_context_files", {})
        if existing:
            first_key = next(iter(existing))
            parts.append(f"\nEXISTING {first_key.upper()} (use as reference, but update/improve it):\n{existing[first_key][:1000]}")

        return "\n".join(parts)
