#!/usr/bin/env python3
"""
Generates boilerplate code and file structures for new projects.
"""

import os
from typing import Dict, List, TypedDict, NotRequired

# --- Project Templates ---

TEMPLATES: Dict[str, Dict[str, str]] = {
    "fastapi": {
        "main.py": """
from fastapi import FastAPI

app = FastAPI(
    title="My FastAPI Project",
    description="A new project generated by MCP.",
    version="0.1.0",
)

@app.get("/")
async def read_root():
    return {"message": "Hello, World!"}

@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str | None = None):
    return {"item_id": item_id, "q": q}
""",
        "pyproject.toml": """
[project]
name = "PROJECT_NAME_PLACEHOLDER"
version = "0.1.0"
description = "A new FastAPI project."
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.12"
dependencies = [
    "fastapi",
    "uvicorn[standard]",
]

[project.optional-dependencies]
dev = ["pytest"]
""",
        "README.md": """
# PROJECT_NAME_PLACEHOLDER

A new FastAPI project generated by Documentation Search Enhanced MCP.

## To run:
1. `uv pip sync`
2. `uv run uvicorn main:app --reload`

## To test:
`uv run pytest`
""",
        ".gitignore": """
__pycache__/
*.pyc
.env
.venv/
dist/
build/
*.egg-info
""",
        "tests/test_main.py": """
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_read_root():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"message": "Hello, World!"}
""",
    },
    "react-vite": {
        "index.html": """
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>PROJECT_NAME_PLACEHOLDER</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>
""",
        "package.json": """
{{
  "name": "PROJECT_NAME_PLACEHOLDER",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {{
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  }},
  "dependencies": {{
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }},
  "devDependencies": {{
    "@types/react": "^18.2.15",
    "@types/react-dom": "^18.2.7",
    "@vitejs/plugin-react": "^4.0.3",
    "eslint": "^8.45.0",
    "eslint-plugin-react": "^7.32.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.3",
    "vite": "^4.4.5"
  }}
}}
""",
        "vite.config.js": """
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
})
""",
        ".gitignore": """
# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Dependency directories
node_modules/
dist/

# IDE files
.idea/
.vscode/

# Environment variables
.env
.env.local
""",
        "src/App.jsx": """
import './App.css'

function App() {
  return (
    <>
      <h1>PROJECT_NAME_PLACEHOLDER</h1>
      <p className="read-the-docs">
        React + Vite project generated by MCP.
      </p>
    </>
  )
}

export default App
""",
        "src/main.jsx": """
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)
""",
        "src/index.css": """
:root {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
}
""",
        "src/App.css": """
#root {
  max-width: 1280px;
  margin: 0 auto;
  padding: 2rem;
  text-align: center;
}
""",
    },
}


class ProjectCreationSummary(TypedDict):
    project_name: str
    template_used: str
    project_path: str
    directories_created: List[str]
    files_created: List[str]
    user_summary: NotRequired[str]


def generate_project(
    project_name: str, template_name: str, base_path: str = "."
) -> ProjectCreationSummary:
    """
    Generates a new project from a template.

    Args:
        project_name: The name of the new project (will be created as a directory).
        template_name: The name of the template to use (e.g., 'fastapi').
        base_path: The path where the project directory will be created.

    Returns:
        A dictionary summarizing the created files and directories.
    """
    if template_name not in TEMPLATES:
        raise ValueError(
            f"Template '{template_name}' not found. Available templates: {list(TEMPLATES.keys())}"
        )

    project_path = os.path.join(base_path, project_name)
    if os.path.exists(project_path):
        raise FileExistsError(f"Directory '{project_path}' already exists.")

    os.makedirs(project_path)

    template = TEMPLATES[template_name]
    created_files = []
    created_dirs = {project_path}

    for file_path, content in template.items():
        # Handle nested directories
        full_path = os.path.join(project_path, file_path)
        dir_name = os.path.dirname(full_path)

        if not os.path.exists(dir_name):
            os.makedirs(dir_name)
            created_dirs.add(dir_name)

        # Replace project name placeholder
        formatted_content = content.replace("PROJECT_NAME_PLACEHOLDER", project_name)

        with open(full_path, "w", encoding="utf-8") as f:
            f.write(formatted_content.strip())

        created_files.append(full_path)

    return {
        "project_name": project_name,
        "template_used": template_name,
        "project_path": project_path,
        "directories_created": sorted(list(created_dirs)),
        "files_created": sorted(created_files),
    }
