"""Project scaffolding utilities for uni-agent-sdk CLI."""

from __future__ import annotations

import re
from dataclasses import dataclass
from pathlib import Path
from textwrap import dedent
from typing import Callable, Dict


class ScaffoldError(Exception):
    """Raised when project scaffolding fails."""


@dataclass
class ScaffoldContext:
    project_name: str
    project_slug: str
    package_name: str
    agent_class: str
    agent_module: str


TemplateBuilder = Callable[[Path, ScaffoldContext], None]


def create_scaffold(base_dir: Path, name: str, template: str = "basic") -> Path:
    """Create a project scaffold under ``base_dir`` using ``template``.

    Returns:
        Path to the newly created project directory.
    """
    templates: Dict[str, TemplateBuilder] = {
        "basic": _build_basic_template,
    }

    builder = templates.get(template)
    if not builder:
        raise ScaffoldError(f"Unsupported template '{template}'")

    context = _build_context(name)
    project_path = base_dir / context.project_slug
    project_path.mkdir(parents=True, exist_ok=False)

    builder(project_path, context)
    return project_path


def _build_context(raw_name: str) -> ScaffoldContext:
    slug = _slugify(raw_name)
    if not slug:
        raise ScaffoldError("Project name must contain alphanumeric characters")

    package = slug.replace("-", "_")
    class_name = _to_camel_case(package) + "Agent"
    module = f"{package}_agent"

    return ScaffoldContext(
        project_name=raw_name,
        project_slug=slug,
        package_name=package,
        agent_class=class_name,
        agent_module=module,
    )


def _build_basic_template(project_dir: Path, ctx: ScaffoldContext) -> None:
    files = {
        "README.md": _render_readme(ctx),
        "requirements.txt": _render_requirements(),
        "pyproject.toml": _render_pyproject(ctx),
        "Dockerfile": _render_dockerfile(ctx),
        ".gitignore": _render_gitignore(),
        ".env.example": _render_env(),
        f"{ctx.package_name}/__init__.py": "",
        f"{ctx.package_name}/config.py": _render_config_module(),
        f"{ctx.package_name}/main.py": _render_main(ctx),
        f"{ctx.package_name}/agents/__init__.py": _render_agents_init(ctx),
        f"{ctx.package_name}/agents/{ctx.agent_module}.py": _render_agent(ctx),
        "tests/__init__.py": "",
        "tests/test_agent.py": _render_test(ctx),
    }

    for relative_path, content in files.items():
        file_path = project_dir / relative_path
        file_path.parent.mkdir(parents=True, exist_ok=True)
        file_path.write_text(_ensure_trailing_newline(content), encoding="utf-8")


def _render_readme(ctx: ScaffoldContext) -> str:
    return dedent(
        f"""
        # {ctx.project_name}

        Project scaffold generated by `uni-agent-sdk`.

        ## Quickstart

        ```bash
        cd {ctx.project_slug}
        python -m venv .venv
        source .venv/bin/activate  # Windows: .venv\\Scripts\\activate
        pip install -r requirements.txt
        cp .env.example .env
        python -m {ctx.package_name}.main
        ```

        ## Customising the agent

        Edit `{ctx.package_name}/agents/{ctx.agent_module}.py` to implement your own logic.

        ## Running tests

        ```bash
        pytest
        ```
        """
    ).strip()


def _render_requirements() -> str:
    return dedent(
        """
        uni-agent-sdk
        aiohttp
        pydantic
        python-dotenv
        aio-pika
        pytest
        """
    ).strip()


def _render_pyproject(ctx: ScaffoldContext) -> str:
    """Render pyproject.toml with proper version configuration."""
    return dedent(
        f'''
        [build-system]
        requires = ["setuptools>=45", "wheel"]
        build-backend = "setuptools.build_meta"

        [project]
        name = "{ctx.project_slug}"
        version = "0.1.0"
        description = "AI agent built with uni-agent-sdk"
        readme = "README.md"
        requires-python = ">=3.8"
        license = {{ text = "MIT" }}
        authors = [
            {{ name = "Your Name", email = "your.email@example.com" }}
        ]
        keywords = ["agent", "ai", "chatbot"]
        dependencies = [
            "uni-agent-sdk>=0.2.0",
            "aiohttp>=3.8.0",
            "pydantic>=2.0.0",
            "python-dotenv>=1.0",
            "aio-pika>=9.5.0",
        ]

        [project.optional-dependencies]
        dev = [
            "pytest>=7.0.0",
            "pytest-asyncio>=0.20.0",
        ]

        [project.urls]
        Homepage = "https://github.com/example/{ctx.project_slug}"
        Repository = "https://github.com/example/{ctx.project_slug}.git"

        [tool.setuptools]
        packages = ["{ctx.package_name}", "{ctx.package_name}.agents"]
        '''
    ).strip()


def _render_dockerfile(ctx: ScaffoldContext) -> str:
    """Render optimized Dockerfile with Aliyun mirrors for Chinese environments."""
    return dedent(
        f"""
        # ============ 编译阶段 ============
        FROM python:3.11-slim as builder

        WORKDIR /build

        # 配置阿里云 APT 源（替换默认源，加速国内构建）
        RUN rm -rf /etc/apt/sources.list.d/* && \\
            echo "deb http://mirrors.aliyun.com/debian/ bookworm main non-free contrib" > /etc/apt/sources.list && \\
            echo "deb-src http://mirrors.aliyun.com/debian/ bookworm main non-free contrib" >> /etc/apt/sources.list && \\
            echo "deb http://mirrors.aliyun.com/debian/ bookworm-updates main non-free contrib" >> /etc/apt/sources.list && \\
            echo "deb-src http://mirrors.aliyun.com/debian/ bookworm-updates main non-free contrib" >> /etc/apt/sources.list && \\
            apt-get update

        # 复制依赖文件
        COPY requirements.txt .

        # 创建虚拟环境并安装依赖（使用阿里云 pip 源）
        RUN python -m venv /opt/venv
        ENV PATH="/opt/venv/bin:$PATH"
        RUN pip install -i https://mirrors.aliyun.com/pypi/simple --no-cache-dir -r requirements.txt

        # ============ 运行阶段 ============
        FROM python:3.11-slim

        WORKDIR /app

        # 配置阿里云 APT 源（替换默认源）
        RUN rm -rf /etc/apt/sources.list.d/* && \\
            echo "deb http://mirrors.aliyun.com/debian/ bookworm main non-free contrib" > /etc/apt/sources.list && \\
            echo "deb-src http://mirrors.aliyun.com/debian/ bookworm main non-free contrib" >> /etc/apt/sources.list && \\
            echo "deb http://mirrors.aliyun.com/debian/ bookworm-updates main non-free contrib" >> /etc/apt/sources.list && \\
            echo "deb-src http://mirrors.aliyun.com/debian/ bookworm-updates main non-free contrib" >> /etc/apt/sources.list && \\
            apt-get update

        # 从构建阶段复制虚拟环境
        COPY --from=builder /opt/venv /opt/venv

        # 设置虚拟环境
        ENV PATH="/opt/venv/bin:$PATH"

        # 复制应用代码
        COPY . .

        # 设置环境变量
        ENV PYTHONUNBUFFERED=1
        ENV PYTHONDONTWRITEBYTECODE=1

        # 健康检查
        HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
            CMD python -c "import sys; sys.exit(0)" || exit 1

        # 入口点
        ENTRYPOINT ["python"]
        CMD ["-u", "/app/main.py"]
        """
    ).strip()


def _render_gitignore() -> str:
    return dedent(
        """
        __pycache__/
        .pytest_cache/
        .venv/
        .env
        *.pyc
        *.pyo
        *.pyd
        build/
        dist/
        *.egg-info/
        """
    ).strip()


def _render_env() -> str:
    return dedent(
        """
        # ============ Platform Configuration ============
        PLATFORM_BASE_URL=http://localhost:8080

        # ============ Agent Credentials ============
        AGENT_API_KEY=your_api_key_here
        AGENT_API_SECRET=your_api_secret_here

        # ============ LLM Configuration ============
        # Supported models: openai/gpt-3.5-turbo, openai/gpt-4, claude-3-opus, etc.
        DEFAULT_MODEL=openai/gpt-3.5-turbo
        OPENROUTER_API_KEY=
        KIMI_API_KEY=

        # ============ Logging ============
        LOG_LEVEL=INFO
        """
    ).strip()


def _render_config_module() -> str:
    return dedent(
        '''
        """Utilities for loading agent configuration from environment variables."""

        import os
        from uni_agent_sdk.utils.config import Config


        def load_config() -> Config:
            """Return a `Config` instance populated from environment variables."""
            return Config(
                platform_base_url=os.getenv("PLATFORM_BASE_URL", "http://localhost:8080"),
                openrouter_api_key=os.getenv("OPENROUTER_API_KEY"),
                kimi_api_key=os.getenv("KIMI_API_KEY"),
                default_model=os.getenv("DEFAULT_MODEL", "openai/gpt-3.5-turbo"),
                rabbitmq_host=os.getenv("RABBITMQ_HOST", "localhost"),
                rabbitmq_port=int(os.getenv("RABBITMQ_PORT", "5673")),
                rabbitmq_user=os.getenv("RABBITMQ_USER", "guest"),
                rabbitmq_password=os.getenv("RABBITMQ_PASSWORD", "guest"),
                rabbitmq_vhost=os.getenv("RABBITMQ_VHOST", "/"),
                log_level=os.getenv("LOG_LEVEL", "INFO"),
            )
        '''
    ).strip()


def _render_main(ctx: ScaffoldContext) -> str:
    return dedent(
        f'''
        """Command line entry point for running the agent."""

        import asyncio
        import os

        from dotenv import load_dotenv

        from .agents.{ctx.agent_module} import {ctx.agent_class}


        async def main() -> None:
            """Load environment, start the agent and keep it running."""
            load_dotenv()
            agent = {ctx.agent_class}()
            try:
                await agent.run()
            except KeyboardInterrupt:
                print("Agent interrupted, shutting down...")


        if __name__ == "__main__":
            os.environ.setdefault("PYTHONASYNCIODEBUG", "0")
            asyncio.run(main())
        '''
    ).strip()


def _render_agents_init(ctx: ScaffoldContext) -> str:
    return dedent(
        f'''
        """Agent package exports."""

        from .{ctx.agent_module} import {ctx.agent_class}

        __all__ = ["{ctx.agent_class}"]
        '''
    ).strip()


def _render_agent(ctx: ScaffoldContext) -> str:
    agent_class = ctx.agent_class
    config_import = "from ..config import load_config"

    return dedent(
        f'''
        """Default agent implementation generated by the scaffold."""

        import os
        from datetime import datetime
        from typing import Any, Dict

        from uni_agent_sdk import Agent, Message, Response

        {config_import}


        class {agent_class}(Agent):
            """Example agent that can be customised by developers."""

            def __init__(self) -> None:
                config = load_config()
                super().__init__(
                    api_key=os.getenv("AGENT_API_KEY", "your_api_key"),
                    api_secret=os.getenv("AGENT_API_SECRET", "your_api_secret"),
                    config=config,
                )

            async def handle_message(self, message: Message, context: Dict[str, Any]) -> Response:
                """Handle incoming messages with simple branching logic."""
                text = message.content.strip()
                if not text:
                    return Response.text("我没有收到有效的内容，请再试一次。")

                lower = text.lower()
                if "hello" in lower or "你好" in text:
                    return Response.text("你好！我是示例智能体，正在待命。")
                if "time" in lower or "时间" in text:
                    now = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
                    return Response.text(f"当前时间：{{now}}")

                return Response.text(f"已接收：{{text}}")
        '''
    ).strip()


def _render_test(ctx: ScaffoldContext) -> str:
    return dedent(
        f"""
        import pytest

        from uni_agent_sdk.models.message import Message

        from {ctx.package_name}.agents import {ctx.agent_class}


        @pytest.mark.asyncio
        async def test_agent_generates_response():
            agent = {ctx.agent_class}()
            message = Message(
                id="msg-1",
                from_uid="user-1",
                to_uid="agent-1",
                conversation_id="conv-1",
                content="hello",
                create_time=0,
            )
            response = await agent.handle_message(message, {{}})
            assert response.content
        """
    ).strip()


def _ensure_trailing_newline(content: str) -> str:
    if not content:
        return "\n"
    return content.rstrip() + "\n"


def _slugify(value: str) -> str:
    slug = re.sub(r"[^a-zA-Z0-9]+", "-", value).strip("-")
    return slug.lower()


def _to_camel_case(value: str) -> str:
    parts = re.split(r"[-_]+", value)
    return "".join(part.capitalize() for part in parts if part)


__all__ = ["create_scaffold", "ScaffoldError"]
