"""Authentication generator for Prism.

This generator creates JWT-based authentication infrastructure including:
- Token service (JWT creation and verification)
- Password service (bcrypt hashing and validation)
- Authentication middleware (FastAPI dependencies)
- Authentication routes (signup, login, refresh, logout, me)
- Authentication schemas (Pydantic models)
"""

from __future__ import annotations

from pathlib import Path

from prism.generators.base import GeneratedFile, GeneratorBase
from prism.spec.stack import FileStrategy
from prism.utils.case_conversion import to_snake_case
from prism.utils.template_engine import TemplateRenderer


class AuthGenerator(GeneratorBase):
    """Generates JWT authentication system for backend."""

    REQUIRED_TEMPLATES = [
        "backend/auth/token_service.py.jinja2",
        "backend/auth/password_service.py.jinja2",
        "backend/auth/middleware_auth.py.jinja2",
        "backend/auth/schemas_auth.py.jinja2",
        "backend/auth/routes_auth.py.jinja2",
        "backend/auth/auth_init.py.jinja2",
        "backend/auth/middleware_init.py.jinja2",
    ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Skip generation if auth is not enabled or preset is not JWT
        if not self.spec.auth.enabled or self.spec.auth.preset != "jwt":
            self.skip_generation = True
            return

        # Initialize template renderer
        self.renderer = TemplateRenderer()
        self.renderer.validate_templates_exist(self.REQUIRED_TEMPLATES)

        # Setup paths for generated auth files
        backend_base = Path(self.spec.generator.backend_output)
        package_name = to_snake_case(self.spec.name)
        package_base = backend_base / package_name

        self.auth_base = package_base / "auth"
        self.middleware_path = package_base / "middleware"
        self.schemas_path = package_base / "schemas"
        self.routes_base = package_base / "api" / "rest"

    def generate_files(self) -> list[GeneratedFile]:
        """Generate all authentication-related files.

        Returns:
            List of generated files with content and strategies
        """
        if getattr(self, "skip_generation", False):
            return []

        files = []

        # Core services
        files.append(self._generate_token_service())
        files.append(self._generate_password_service())

        # Middleware
        files.append(self._generate_jwt_middleware())

        # Routes
        files.append(self._generate_auth_routes())

        # Schemas
        files.append(self._generate_auth_schemas())

        # Init files
        files.append(self._generate_auth_init())
        files.append(self._generate_middleware_init())

        return files

    def _generate_token_service(self) -> GeneratedFile:
        """Generate JWT token creation and verification service.

        Returns:
            GeneratedFile for token_service.py
        """
        project_name = to_snake_case(self.spec.name)
        config = self.spec.auth

        content = self.renderer.render_file(
            "backend/auth/token_service.py.jinja2",
            context={
                "project_name": project_name,
                "algorithm": config.algorithm,
                "access_token_expire_minutes": config.access_token_expire_minutes,
                "refresh_token_expire_days": config.refresh_token_expire_days,
            },
        )

        return GeneratedFile(
            path=self.auth_base / "token_service.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="JWT token service",
        )

    def _generate_password_service(self) -> GeneratedFile:
        """Generate password hashing and validation service.

        Returns:
            GeneratedFile for password_service.py
        """
        config = self.spec.auth

        content = self.renderer.render_file(
            "backend/auth/password_service.py.jinja2",
            context={
                "min_length": config.password_min_length,
                "require_uppercase": str(config.password_require_uppercase),
                "require_lowercase": str(config.password_require_lowercase),
                "require_number": str(config.password_require_number),
                "require_special": str(config.password_require_special),
            },
        )

        return GeneratedFile(
            path=self.auth_base / "password_service.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Password hashing service",
        )

    def _generate_jwt_middleware(self) -> GeneratedFile:
        """Generate FastAPI authentication middleware and dependencies.

        Returns:
            GeneratedFile for middleware/auth.py
        """
        project_name = to_snake_case(self.spec.name)
        user_model = self.spec.auth.user_model
        user_model_snake = to_snake_case(user_model)

        content = self.renderer.render_file(
            "backend/auth/middleware_auth.py.jinja2",
            context={
                "project_name": project_name,
                "user_model": user_model,
                "user_model_snake": user_model_snake,
            },
        )

        return GeneratedFile(
            path=self.middleware_path / "auth.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="JWT authentication middleware",
        )

    def _generate_auth_schemas(self) -> GeneratedFile:
        """Generate Pydantic schemas for authentication.

        Returns:
            GeneratedFile for schemas/auth.py
        """
        username_field = self.spec.auth.username_field
        is_email = username_field == "email"

        content = self.renderer.render_file(
            "backend/auth/schemas_auth.py.jinja2",
            context={
                "username_field": username_field,
                "username_field_title": username_field.title(),
                "is_email": is_email,
            },
        )

        return GeneratedFile(
            path=self.schemas_path / "auth.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Auth Pydantic schemas",
        )

    def _generate_auth_routes(self) -> GeneratedFile:
        """Generate FastAPI authentication routes.

        Returns:
            GeneratedFile for api/rest/auth.py
        """
        project_name = to_snake_case(self.spec.name)
        user_model = self.spec.auth.user_model
        user_model_snake = to_snake_case(user_model)
        username_field = self.spec.auth.username_field
        default_role = self.spec.auth.default_role

        content = self.renderer.render_file(
            "backend/auth/routes_auth.py.jinja2",
            context={
                "project_name": project_name,
                "user_model": user_model,
                "user_model_snake": user_model_snake,
                "username_field": username_field,
                "username_field_title": username_field.title(),
                "default_role": default_role,
            },
        )

        return GeneratedFile(
            path=self.routes_base / "auth.py",
            content=content,
            strategy=FileStrategy.GENERATE_ONCE,  # Allow customization
            description="Auth API routes",
        )

    def _generate_auth_init(self) -> GeneratedFile:
        """Generate __init__.py for auth module.

        Returns:
            GeneratedFile for auth/__init__.py
        """
        project_name = to_snake_case(self.spec.name)

        content = self.renderer.render_file(
            "backend/auth/auth_init.py.jinja2",
            context={
                "project_name": project_name,
            },
        )

        return GeneratedFile(
            path=self.auth_base / "__init__.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Auth module init",
        )

    def _generate_middleware_init(self) -> GeneratedFile:
        """Generate __init__.py for middleware module.

        Returns:
            GeneratedFile for middleware/__init__.py
        """
        project_name = to_snake_case(self.spec.name)

        content = self.renderer.render_file(
            "backend/auth/middleware_init.py.jinja2",
            context={
                "project_name": project_name,
            },
        )

        return GeneratedFile(
            path=self.middleware_path / "__init__.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Middleware module init",
        )
