"""
Layer 2 LLM enhancement for skill generation.

Isolated module -- imported only when --layer 2 is requested.
Primary path: claude CLI subprocess (uses existing Claude Code subscription).
Fallback path: anthropic SDK (for CI environments like GitHub Actions).
"""

import shutil
import subprocess
import sys

from lap.core.compilers.skill import SkillOutput


ENHANCE_PROMPT = """You are enhancing a Claude Code skill for an API. Given the LAP spec below,
generate ADDITIONAL content to supplement (not replace) the existing skill document.

Use ### (level 3) headings only -- never ## (level 2). The output will be appended to an existing
document that already has ## sections.

Generate these sections:

### Workflow Playbooks
3-5 common multi-step workflows as numbered lists under descriptive ### headings.
Focus on tasks that chain multiple endpoints together.

### Response Interpretation
One line per endpoint category: how to interpret responses.
Focus on pagination patterns, error codes, nested objects, and status fields.

### Edge Cases and Gotchas
5-10 practical warnings: rate limits, deprecated fields, required-but-undocumented params,
common mistakes, and order-of-operations requirements.

IMPORTANT: Do NOT generate question-to-endpoint mappings -- the existing skill already has a
comprehensive endpoint catalog. Do NOT repeat endpoint names or paths.

Return ONLY the markdown content -- no preamble, no code fences.

LAP Spec:
{spec_text}
"""


def _has_claude_cli() -> bool:
    """Check whether the claude CLI is on PATH."""
    return shutil.which("claude") is not None


def _enhance_via_cli(prompt: str) -> str:
    """Call claude CLI as a subprocess, piping the prompt via stdin."""
    try:
        result = subprocess.run(
            ["claude", "-p", "--model", "opus", "--output-format", "text", "--verbose"],
            input=prompt,
            capture_output=True,
            text=True,
            timeout=300,  # 5-minute timeout
            encoding="utf-8",
        )
    except subprocess.TimeoutExpired:
        raise RuntimeError("claude CLI timed out after 5 minutes.")

    if result.returncode != 0:
        stderr = result.stderr.strip() if result.stderr else "unknown error"
        raise RuntimeError(f"claude CLI exited with code {result.returncode}: {stderr}")

    return result.stdout


def _enhance_via_sdk(prompt: str, api_key: str = None) -> str:
    """Fallback: call the Anthropic SDK directly (for CI environments)."""
    try:
        import anthropic
    except ImportError:
        raise ImportError(
            "Layer 2 requires either the claude CLI or the 'anthropic' package. "
            "Install the CLI (https://docs.anthropic.com/en/docs/claude-code) "
            "or run: pip install anthropic"
        )

    client_kwargs = {}
    if api_key:
        client_kwargs["api_key"] = api_key

    client = anthropic.Anthropic(**client_kwargs)
    try:
        message = client.messages.create(
            model="claude-opus-4-6",
            max_tokens=4096,
            messages=[{"role": "user", "content": prompt}],
        )
    except anthropic.APITimeoutError:
        raise RuntimeError("Anthropic API timed out. Check your network connection and try again.")
    except anthropic.RateLimitError:
        raise RuntimeError("Anthropic API rate limit reached. Wait a moment and try again.")
    except anthropic.APIError as e:
        raise RuntimeError(f"Anthropic API error: {e}")

    return message.content[0].text


def enhance_skill(spec, skill: SkillOutput, api_key: str = None) -> SkillOutput:
    """Add LLM-generated content to a Layer 1 skill.

    Primary: claude CLI subprocess. Fallback: anthropic SDK.
    Raises ImportError if neither is available, RuntimeError on failure.
    """
    from lap.core.formats.lap import LAPSpec
    from lap.core.utils import count_tokens

    # Generate lean spec text for context
    spec_text = spec.to_lap(lean=True)

    # Guard against oversized prompts
    prompt_tokens = count_tokens(spec_text)
    if prompt_tokens > 150_000:
        print(
            f"Warning: spec is {prompt_tokens:,} tokens, exceeding 150k limit. "
            "Returning Layer 1 skill unchanged.",
            file=sys.stderr,
        )
        return skill

    prompt = ENHANCE_PROMPT.format(spec_text=spec_text)

    # Primary path: claude CLI
    if _has_claude_cli():
        enhanced_content = _enhance_via_cli(prompt)
    else:
        # Fallback: anthropic SDK (deferred import inside _enhance_via_sdk)
        enhanced_content = _enhance_via_sdk(prompt, api_key)

    # Append LLM-enhanced content after existing SKILL.md (additive, not destructive)
    skill_md = skill.file_map[skill.main_file]

    # Strip any ## headings from LLM output (force ### only)
    enhanced_content = _demote_headings(enhanced_content)

    # Append under a new ## section
    skill_md = skill_md.rstrip() + "\n\n## LLM-Enhanced Guidance\n\n" + enhanced_content.strip() + "\n"

    # Update file map
    new_file_map = dict(skill.file_map)
    new_file_map[skill.main_file] = skill_md

    # Recalculate tokens
    total_tokens = sum(count_tokens(content) for content in new_file_map.values())

    return SkillOutput(
        name=skill.name,
        main_file=skill.main_file,
        file_map=new_file_map,
        token_count=total_tokens,
        endpoint_count=skill.endpoint_count,
    )


def _demote_headings(content: str) -> str:
    """Ensure all headings in LLM output are ### or lower (never ##)."""
    import re
    lines = content.split("\n")
    result = []
    for line in lines:
        if re.match(r'^## [^#]', line):
            line = "#" + line  # ## -> ###
        result.append(line)
    return "\n".join(result)
