"""Protocol generator core logic."""

import shutil
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, cast

from cokodo_agent.config import AI_TOOLS, TECH_STACKS


def generate_protocol(
    source_path: Path,
    target_path: Path,
    config: Dict[str, Any],
    force: bool = False,
) -> None:
    """
    Generate .agent protocol in target directory.

    Args:
        source_path: Path to source protocol files
        target_path: Target project directory
        config: Configuration dictionary from prompts
        force: Overwrite existing .agent if True
    """

    agent_dir = target_path / ".agent"

    # Remove existing if force
    if agent_dir.exists():
        if force:
            shutil.rmtree(agent_dir)
        else:
            raise FileExistsError(f".agent already exists at {agent_dir}")

    # Copy protocol files
    shutil.copytree(source_path, agent_dir)

    # Customize project files
    _customize_context(agent_dir, config)
    _customize_tech_stack(agent_dir, config)

    # Generate AI tool adapters
    _generate_adapters(target_path, config)


def _customize_context(agent_dir: Path, config: Dict[str, Any]) -> None:
    """Customize project/context.md with user input."""

    context_file = agent_dir / "project" / "context.md"

    content = f"""# Project Context

## Project Name

{config.get('project_name', 'Unnamed Project')}

## Description

{config.get('description', '[TODO: Add project description]')}

## Current Status

[TODO: Describe current development status]

## Key Features

[TODO: List main features]

## Business Rules

[TODO: Document important business logic]

---

*Generated by cokodo-agent on {datetime.now().strftime('%Y-%m-%d')}*
"""

    context_file.write_text(content, encoding="utf-8")


def _customize_tech_stack(agent_dir: Path, config: Dict[str, Any]) -> None:
    """Customize project/tech-stack.md with user input."""

    tech_stack_file = agent_dir / "project" / "tech-stack.md"

    stack_key = config.get("tech_stack", "other")
    stack_name = TECH_STACKS.get(stack_key, "Other")

    # Stack-specific recommendations
    stack_recommendations = {
        "python": """
## Recommended Tools

- Package Manager: uv / pip
- Linting: ruff
- Testing: pytest
- Type Checking: mypy
""",
        "rust": """
## Recommended Tools

- Package Manager: cargo
- Linting: clippy
- Testing: cargo test
- Formatting: rustfmt
""",
        "qt": """
## Recommended Tools

- Build System: CMake / qmake
- IDE: Qt Creator
- Testing: Qt Test
""",
        "mixed": """
## Recommended Tools

### Python
- Package Manager: uv / pip
- Linting: ruff

### Rust
- Package Manager: cargo
- Linting: clippy
""",
    }

    recommendations = stack_recommendations.get(
        stack_key,
        """
## Recommended Tools

[TODO: Add your tooling recommendations]
""",
    )

    content = f"""# Tech Stack

## Primary Stack

{stack_name}

## Language Versions

[TODO: Specify versions, e.g., Python 3.11+, Rust 1.70+]

## Key Dependencies

[TODO: List main dependencies]

{recommendations}

## Development Environment

[TODO: Describe development setup]

---

*Generated by cokodo-agent on {datetime.now().strftime('%Y-%m-%d')}*
"""

    tech_stack_file.write_text(content, encoding="utf-8")


def _project_name_from_context(agent_dir: Path) -> str:
    """Read project name from .agent/project/context.md if present."""
    context_file = agent_dir / "project" / "context.md"
    if not context_file.exists():
        return "Project"
    text = context_file.read_text(encoding="utf-8")
    in_name_section = False
    for line in text.splitlines():
        stripped = line.strip()
        if "## " in stripped and "name" in stripped.lower():
            in_name_section = True
            continue
        if in_name_section:
            if stripped.startswith(("#", "|", "-", ">", "---", "[")):
                break
            if stripped:
                return stripped.replace("{{PROJECT_NAME}}", "Project").strip() or "Project"
    return "Project"


def generate_adapters_for_tools(
    target_path: Path,
    agent_dir: Path,
    tool_keys: list[str],
) -> None:
    """
    Generate IDE adapter entry files for existing .agent directory.

    Each adapter is a thin pointer that instructs the IDE to load
    ``.agent/start-here.md`` as the protocol entry point.  The actual
    protocol content lives exclusively inside ``.agent/``; adapters
    never duplicate it.

    Args:
        target_path: Project root (parent of .agent)
        agent_dir: Path to .agent directory
        tool_keys: One or more of: cursor, claude, copilot, gemini
    """
    project_name = _project_name_from_context(agent_dir)

    _GENERATORS: dict[str, Any] = {
        "cursor": _generate_cursor_adapter,
        "claude": _generate_claude_adapter,
        "copilot": _generate_copilot_adapter,
        "gemini": _generate_gemini_adapter,
    }

    for tool_key in tool_keys:
        if tool_key not in AI_TOOLS:
            continue
        tool_info = AI_TOOLS[tool_key]
        if tool_info["file"] is None:
            continue
        gen_fn = _GENERATORS.get(tool_key)
        if gen_fn is None:
            continue
        gen_fn(target_path, project_name)


def _generate_adapters(target_path: Path, config: Dict[str, Any]) -> None:
    """Generate AI tool adapter files (called from ``generate_protocol``)."""

    ai_tools = config.get("ai_tools", [])
    if not ai_tools:
        return

    agent_dir = target_path / ".agent"
    project_name = config.get("project_name", "Project")

    _GENERATORS: dict[str, Any] = {
        "cursor": _generate_cursor_adapter,
        "claude": _generate_claude_adapter,
        "copilot": _generate_copilot_adapter,
        "gemini": _generate_gemini_adapter,
    }

    for tool_key in ai_tools:
        if tool_key not in AI_TOOLS:
            continue
        tool_info = AI_TOOLS[tool_key]
        if tool_info["file"] is None:
            continue
        gen_fn = _GENERATORS.get(tool_key)
        if gen_fn is None:
            continue
        gen_fn(target_path, project_name)


# ---------------------------------------------------------------------------
# Per-IDE adapter generators
# ---------------------------------------------------------------------------

def _generate_cursor_adapter(target_path: Path, project_name: str) -> None:
    """Generate ``.cursor/rules/agent-protocol.mdc`` with YAML frontmatter.

    Official spec (2026): https://docs.cursor.com/context/rules
    Format: ``.mdc`` files in ``.cursor/rules/`` with YAML frontmatter
    containing ``description``, ``globs`` (optional), and ``alwaysApply``.
    """
    rules_dir = target_path / ".cursor" / "rules"
    rules_dir.mkdir(parents=True, exist_ok=True)

    content = f"""---
description: AI Agent Collaboration Protocol for {project_name} - read .agent/start-here.md first
alwaysApply: true
---

# Agent Protocol

This project uses AI Agent Collaboration Protocol.
**Read `.agent/start-here.md` first** to establish the full context.

## Essential Files

1. `.agent/start-here.md` — Protocol entry point (read every session)
2. `.agent/project/context.md` — Project business context
3. `.agent/core/core-rules.md` — Non-negotiable core principles

## Key Rules

- Encoding: UTF-8 (explicit declaration required)
- Paths: always use forward slash `/`
- Test data: must use `autotest_` prefix
- No external CDN links
- Check `.agent/project/known-issues.md` before starting work
"""
    (rules_dir / "agent-protocol.mdc").write_text(content, encoding="utf-8")


def _generate_claude_adapter(target_path: Path, project_name: str) -> None:
    """Generate ``CLAUDE.md`` at project root.

    Official spec (2026): https://docs.anthropic.com/en/docs/claude-code
    Format: ``CLAUDE.md`` at project root, auto-loaded every Claude Code session.
    Additional modular rules can go in ``.claude/rules/*.md`` (optional).
    """
    content = f"""# {project_name}

This project uses AI Agent Collaboration Protocol.

## First Step

Read `.agent/start-here.md` to establish the full collaboration context.
This is the single entry point for all AI agents working on this project.

## Essential Files

- `.agent/start-here.md` — Protocol entry point (read every session)
- `.agent/project/context.md` — Project business context
- `.agent/core/core-rules.md` — Non-negotiable core principles
- `.agent/project/tech-stack.md` — Technology stack decisions

## Key Rules

- Encoding: UTF-8 (explicit declaration required)
- Paths: always use forward slash `/`
- Test data: must use `autotest_` prefix
- No external CDN links
- Check `.agent/project/known-issues.md` before starting work
"""
    (target_path / "CLAUDE.md").write_text(content, encoding="utf-8")


def _generate_copilot_adapter(target_path: Path, project_name: str) -> None:
    """Generate ``AGENTS.md`` at project root.

    Official spec (2026): https://docs.github.com/en/copilot
    ``AGENTS.md`` is recognized by GitHub Copilot agent mode.
    Copilot also supports ``CLAUDE.md`` and ``GEMINI.md`` as instruction sources.
    """
    content = f"""# {project_name}

This project uses AI Agent Collaboration Protocol.

## First Step

Read `.agent/start-here.md` to establish the full collaboration context.
This is the single entry point for all AI agents working on this project.

## Essential Files

- `.agent/start-here.md` — Protocol entry point (read every session)
- `.agent/project/context.md` — Project business context
- `.agent/core/core-rules.md` — Non-negotiable core principles
- `.agent/project/tech-stack.md` — Technology stack decisions

## Key Rules

- Encoding: UTF-8 (explicit declaration required)
- Paths: always use forward slash `/`
- Test data: must use `autotest_` prefix
- No external CDN links

## Before Coding

1. Read `.agent/project/context.md` for business context
2. Check `.agent/project/tech-stack.md` for tech decisions
3. Check `.agent/project/known-issues.md` for known pitfalls
"""
    (target_path / "AGENTS.md").write_text(content, encoding="utf-8")


def _generate_gemini_adapter(target_path: Path, project_name: str) -> None:
    """Generate ``GEMINI.md`` at project root using ``@file`` import syntax.

    Official spec (2026): https://google-gemini.github.io/gemini-cli/docs/cli/gemini-md.html
    Format: ``GEMINI.md`` at project root, auto-loaded by Gemini CLI / Code Assist.
    Supports ``@relative/path.md`` to inline external file contents.
    """
    content = f"""# {project_name}

This project uses AI Agent Collaboration Protocol.
The files below are auto-imported for full context.

@.agent/start-here.md

@.agent/project/context.md

@.agent/core/core-rules.md

## Key Rules

- Encoding: UTF-8 (explicit declaration required)
- Paths: always use forward slash `/`
- Test data: must use `autotest_` prefix
- No external CDN links
- Check `.agent/project/known-issues.md` before starting work
"""
    (target_path / "GEMINI.md").write_text(content, encoding="utf-8")
