"""
Project Template Generator - Creates all necessary project files for GitHub-ready projects

Generates:
- pyproject.toml (build system, project metadata, tool configs)
- setup.py (legacy packaging)
- setup.cfg (additional setup)
- .github/workflows/ (CI/CD pipelines)
- pytest.ini (test configuration)
- .pre-commit-config.yaml (code quality hooks)
- Makefile (development tasks)
- LICENSE (MIT by default)
- CONTRIBUTING.md (contribution guidelines)
- CHANGELOG.md (version history)
- Dockerfile & docker-compose.yml (containerization)
- .env.example (environment template)
- .dockerignore (Docker exclusions)
"""

from datetime import datetime
from typing import List, Optional


class ProjectTemplateGenerator:
    """Generate comprehensive project templates and configuration files"""

    @staticmethod
    def generate_pyproject_toml(
        project_name: str,
        description: str = "",
        version: str = "0.1.0",
        author: str = "Generated by Socrates",
        dependencies: Optional[List[str]] = None,
        dev_dependencies: Optional[List[str]] = None,
        python_version: str = "3.9",
    ) -> str:
        """
        Generate pyproject.toml with modern Python project configuration.

        Includes:
        - Build system (setuptools, wheel)
        - Project metadata
        - Dependencies
        - Tool configurations (ruff, black, mypy, pytest)
        """
        if dependencies is None:
            dependencies = []
        if dev_dependencies is None:
            dev_dependencies = ["pytest>=7.0", "black>=23.0", "ruff>=0.1.0", "mypy>=1.0"]

        # Extract version constraints from dependencies
        deps_str = "\n".join([f'    "{dep}"' for dep in dependencies])
        dev_deps_str = "\n".join([f'    "{dep}"' for dep in dev_dependencies])

        pyproject = f"""[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "{project_name}"
version = "{version}"
description = "{description}"
readme = "README.md"
requires-python = ">={python_version}"
authors = [
    {{name = "{author}"}}
]
keywords = ["python", "project"]
classifiers = [
    "Development Status :: 3 - Alpha",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
]

dependencies = [
{deps_str}
]

[project.optional-dependencies]
dev = [
{dev_deps_str}
]

[tool.setuptools]
packages = ["src"]

[tool.black]
line-length = 100
target-version = ["py39", "py310", "py311"]
include = '\\.pyi?$'

[tool.ruff]
line-length = 100
target-version = "py39"
select = ["E", "F", "W", "I", "N"]
ignore = ["E501"]

[tool.mypy]
python_version = "{python_version}"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = false

[tool.pytest.ini_options]
minversion = "7.0"
addopts = "-v --tb=short --strict-markers"
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
markers = [
    "unit: unit tests",
    "integration: integration tests",
]

[tool.isort]
profile = "black"
line_length = 100
"""
        return pyproject

    @staticmethod
    def generate_setup_py(
        project_name: str,
        version: str = "0.1.0",
        description: str = "",
        author: str = "Generated by Socrates",
    ) -> str:
        """Generate setup.py for backwards compatibility with older pip versions."""
        setup_py = (
            '''#!/usr/bin/env python
"""Setup script for packaging."""

from setuptools import setup, find_packages

setup(
    name="'''
            + project_name
            + '''",
    version="'''
            + version
            + '''",
    description="'''
            + description
            + '''",
    author="'''
            + author
            + """",
    packages=find_packages(where="src"),
    package_dir={"": "src"},
    python_requires=">=3.9",
    install_requires=[],
    extras_require={
        "dev": [
            "pytest>=7.0",
            "black>=23.0",
            "ruff>=0.1.0",
            "mypy>=1.0",
        ],
    },
)
"""
        )
        return setup_py

    @staticmethod
    def generate_setup_cfg() -> str:
        """Generate setup.cfg for additional configuration."""
        return """[metadata]
name = project_name
version = 0.1.0

[options]
packages = find:
python_requires = >=3.9

[options.packages.find]
where = src

[bdist_wheel]
universal = False
"""

    @staticmethod
    def generate_github_workflows() -> dict:
        """Generate .github/workflows/ CI/CD pipeline files."""
        workflows = {}

        # CI workflow - Run tests
        ci_workflow = """name: Tests

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12"]

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -e ".[dev]"

      - name: Run tests
        run: pytest -v --tb=short

      - name: Upload coverage
        if: matrix.python-version == '3.11'
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage.xml
"""
        workflows[".github/workflows/ci.yml"] = ci_workflow

        # Lint workflow - Code quality checks
        lint_workflow = """name: Lint

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  lint:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.11"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install black ruff mypy

      - name: Format check (black)
        run: black --check .

      - name: Lint check (ruff)
        run: ruff check .

      - name: Type check (mypy)
        run: mypy . --ignore-missing-imports || true
"""
        workflows[".github/workflows/lint.yml"] = lint_workflow

        # Publish workflow - Publish to PyPI
        publish_workflow = """name: Publish

on:
  release:
    types: [created]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.11"

      - name: Install build dependencies
        run: |
          python -m pip install --upgrade pip
          pip install build wheel

      - name: Build distribution
        run: python -m build

      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_API_TOKEN }}
"""
        workflows[".github/workflows/publish.yml"] = publish_workflow

        return workflows

    @staticmethod
    def generate_pytest_ini() -> str:
        """Generate pytest.ini configuration file."""
        return """[pytest]
minversion = 7.0
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts = -v --tb=short --strict-markers
testpaths = tests
markers =
    unit: Unit tests
    integration: Integration tests
    slow: Slow running tests
"""

    @staticmethod
    def generate_pre_commit_config() -> str:
        """Generate .pre-commit-config.yaml for pre-commit hooks."""
        return """repos:
  - repo: https://github.com/psf/black
    rev: 23.3.0
    hooks:
      - id: black
        language_version: python3

  - repo: https://github.com/charliermarsh/ruff-pre-commit
    rev: v0.0.260
    hooks:
      - id: ruff
        args: ["--fix"]

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.0.1
    hooks:
      - id: mypy
        additional_dependencies: ["types-all"]
        args: ["--ignore-missing-imports"]

  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
        args: ["--maxkb=500"]
"""

    @staticmethod
    def generate_makefile(project_name: str = "project") -> str:
        """Generate Makefile with common development tasks."""
        makefile = """.PHONY: help install install-dev test lint format clean build publish

help:
\t@echo "Available commands:"
\t@echo "  make install       - Install project in production mode"
\t@echo "  make install-dev   - Install project with dev dependencies"
\t@echo "  make test          - Run tests"
\t@echo "  make lint          - Run linting checks"
\t@echo "  make format        - Format code with black and ruff"
\t@echo "  make type-check    - Run mypy type checking"
\t@echo "  make clean         - Clean build artifacts"
\t@echo "  make build         - Build distribution packages"

install:
\tpip install -e .

install-dev:
\tpip install -e ".[dev]"
\tpre-commit install

test:
\tpytest

lint:
\truff check .
\tblack --check .
\tmypy . --ignore-missing-imports || true

format:
\tblack .
\truff check . --fix

type-check:
\tmypy . --ignore-missing-imports

clean:
\trm -rf build/
\trm -rf dist/
\trm -rf *.egg-info/
\trm -rf .pytest_cache/
\trm -rf .mypy_cache/
\trm -rf htmlcov/
\tfind . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true

build: clean
\tpython -m build

publish: build
\ttwine upload dist/*
"""
        return makefile

    @staticmethod
    def generate_license(license_type: str = "MIT", author: str = "", year: str = "") -> str:
        """Generate LICENSE file (default: MIT)."""
        if not year:
            year = str(datetime.now().year)
        if not author:
            author = "Project Contributors"

        if license_type.upper() == "MIT":
            return f"""MIT License

Copyright (c) {year} {author}

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
        elif license_type.upper() == "APACHE":
            return """Apache License
Version 2.0, January 2004

(see https://www.apache.org/licenses/LICENSE-2.0.txt for full text)
"""
        else:
            return "# License file - Please specify license type"

    @staticmethod
    def generate_contributing_md(project_name: str = "Project") -> str:
        """Generate CONTRIBUTING.md guidelines."""
        return f"""# Contributing to {project_name}

Thank you for your interest in contributing to {project_name}! We welcome contributions from everyone.

## How to Contribute

### Reporting Bugs
- Check existing issues to avoid duplicates
- Provide a clear description and steps to reproduce
- Include your environment details (OS, Python version, etc.)

### Suggesting Enhancements
- Explain the enhancement and use case
- Provide examples of how it would work
- Explain why this enhancement would be useful

### Submitting Pull Requests
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Write or update tests as needed
5. Ensure all tests pass (`make test`)
6. Ensure code is formatted (`make format`)
7. Commit with clear messages
8. Push to your fork
9. Submit a pull request with a clear description

## Development Setup

```bash
git clone https://github.com/yourusername/{project_name}.git
cd {project_name}
make install-dev
```

## Code Style

We follow [PEP 8](https://www.python.org/dev/peps/pep-0008/) with:
- Line length: 100 characters
- Use type hints
- Document all public functions

We use these tools:
- **black** for formatting
- **ruff** for linting
- **mypy** for type checking

Run `make format` and `make lint` before submitting.

## Testing

All new features must include tests:

```bash
make test
```

Aim for >80% code coverage.

## License

By contributing, you agree that your contributions will be licensed under its MIT License.

## Questions?

Feel free to open an issue for any questions.
"""

    @staticmethod
    def generate_changelog_md() -> str:
        """Generate CHANGELOG.md template."""
        current_year = datetime.now().year
        return f"""# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- New features

### Changed
- Changes to existing functionality

### Deprecated
- Soon-to-be removed features

### Removed
- Removed features

### Fixed
- Bug fixes

### Security
- Security fixes

## [0.1.0] - {current_year}-01-01

### Added
- Initial release
"""

    @staticmethod
    def generate_env_example() -> str:
        """Generate .env.example template."""
        return """# Environment Configuration Template
# Copy this file to .env and fill in your values

# Application Settings
APP_NAME=my-project
DEBUG=False
LOG_LEVEL=INFO

# Database (if applicable)
DATABASE_URL=postgresql://user:password@localhost:5432/dbname

# API Keys (if applicable)
API_KEY=your-api-key-here
SECRET_KEY=your-secret-key-here

# External Services
GITHUB_TOKEN=your-github-token
"""

    @staticmethod
    def generate_dockerfile(python_version: str = "3.11", project_type: str = "api") -> str:
        """Generate multi-stage Dockerfile for production deployment."""
        dockerfile = f"""# Stage 1: Builder
FROM python:{python_version}-slim as builder

WORKDIR /build

# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \\
    build-essential \\
    && rm -rf /var/lib/apt/lists/*

# Copy requirements
COPY requirements.txt .

# Build wheels
RUN pip install --upgrade pip && \\
    pip wheel --no-cache-dir --no-deps --wheel-dir /build/wheels -r requirements.txt


# Stage 2: Runtime
FROM python:{python_version}-slim

WORKDIR /app

# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \\
    curl \\
    && rm -rf /var/lib/apt/lists/*

# Create non-root user
RUN useradd -m -u 1000 appuser

# Copy wheels from builder
COPY --from=builder /build/wheels /wheels

# Install wheels
COPY requirements.txt .
RUN pip install --upgrade pip && \\
    pip install --no-cache /wheels/*

# Copy application code
COPY . .

# Change ownership to appuser
RUN chown -R appuser:appuser /app

# Switch to non-root user
USER appuser

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
    CMD curl -f http://localhost:8000/health || exit 1

# Run application
EXPOSE 8000
CMD ["python", "main.py"]
"""
        return dockerfile

    @staticmethod
    def generate_docker_compose(project_name: str = "project", python_version: str = "3.11") -> str:
        """Generate docker-compose.yml for local development."""
        docker_compose = f"""version: "3.9"

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: {project_name}-app
    ports:
      - "8000:8000"
    environment:
      - PYTHONUNBUFFERED=1
      - DEBUG=True
    volumes:
      - .:/app
    command: python main.py
    depends_on:
      - postgres
      - redis
    networks:
      - {project_name}-network

  postgres:
    image: postgres:15-alpine
    container_name: {project_name}-db
    environment:
      POSTGRES_DB: {project_name}_db
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - {project_name}-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: {project_name}-cache
    ports:
      - "6379:6379"
    networks:
      - {project_name}-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:

networks:
  {project_name}-network:
    driver: bridge
"""
        return docker_compose

    @staticmethod
    def generate_dockerignore() -> str:
        """Generate .dockerignore file for optimized Docker builds."""
        return """# Git
.git
.gitignore
.gitattributes

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
ENV/
.venv
*.egg-info/
dist/
build/

# IDEs
.vscode/
.idea/
*.swp
*.swo
*.sublime-project
*.sublime-workspace

# Testing
.pytest_cache/
.coverage
htmlcov/
.tox/

# OS
.DS_Store
Thumbs.db

# Project specific
.env
.env.local
*.log
*.pid
.mypy_cache/
.ruff_cache/

# Documentation
docs/_build/

# CI/CD
.github/
.gitlab-ci.yml
.travis.yml

# Development
docker-compose.override.yml
"""
