"""Router generator for Prism.

Generates React Router configuration, App.tsx with RouterProvider,
and main.tsx with urql Provider for frontend applications.
"""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

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

if TYPE_CHECKING:
    from prism.spec.model import ModelSpec


class RouterGenerator(GeneratorBase):
    """Generator for React Router configuration and app entry files."""

    REQUIRED_TEMPLATES = [
        "frontend/router/router.tsx.jinja2",
        "frontend/router/App.tsx.jinja2",
        "frontend/router/main_urql.tsx.jinja2",
        "frontend/router/main_apollo.tsx.jinja2",
    ]

    def __init__(self, *args, **kwargs) -> None:  # type: ignore[no-untyped-def]
        super().__init__(*args, **kwargs)
        frontend_base = Path(self.spec.generator.frontend_output)
        self.src_path = frontend_base

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

    def generate_files(self) -> list[GeneratedFile]:
        """Generate router, App.tsx, and main.tsx files."""
        # Only generate if there are frontend-enabled models
        frontend_models = [m for m in self.spec.models if m.frontend.enabled]
        if not frontend_models:
            return []

        return [
            self._generate_router(frontend_models),
            self._generate_app(),
            self._generate_main(),
        ]

    def _generate_router(self, models: list[ModelSpec]) -> GeneratedFile:
        """Generate router.tsx with routes for all models."""
        imports = []
        routes = []

        # Add auth routes if auth is enabled
        auth_enabled = self.spec.auth.enabled
        auth_config = self.spec.auth
        if auth_enabled:
            imports.append("import { Login } from './pages/Login';")
            imports.append("import { Signup } from './pages/Signup';")
            if auth_config.password_reset:
                imports.append(
                    "import { ForgotPasswordForm } from './components/auth/ForgotPasswordForm';"
                )
                imports.append("import ResetPassword from './pages/ResetPassword';")
            if auth_config.email_verification:
                imports.append("import VerifyEmail from './pages/VerifyEmail';")
            if auth_config.oauth_providers:
                imports.append("import AuthCallback from './pages/AuthCallback';")

        for model in models:
            snake_name = to_snake_case(model.name)
            kebab_name = to_kebab_case(snake_name)
            plural_name = pluralize(model.name)
            plural_kebab = pluralize(kebab_name)
            ops = model.frontend.operations
            has_form = model.frontend.generate_form
            has_detail = model.frontend.generate_detail_view

            if ops.list:
                imports.append(f"import {plural_name}ListPage from './pages/{plural_kebab}';")
                routes.append(
                    f"  {{ path: '/{plural_kebab}', element: <{plural_name}ListPage /> }},"
                )

            # Only generate detail route if both operation is enabled AND detail component exists
            if ops.read and has_detail:
                imports.append(f"import {model.name}DetailPage from './pages/{plural_kebab}/[id]';")
                routes.append(
                    f"  {{ path: '/{plural_kebab}/:id', element: <{model.name}DetailPage /> }},"
                )

            # Only generate create/edit routes if both operation is enabled AND form exists
            if ops.create and has_form:
                imports.append(f"import {model.name}CreatePage from './pages/{plural_kebab}/new';")
                routes.append(
                    f"  {{ path: '/{plural_kebab}/new', element: <{model.name}CreatePage /> }},"
                )

            if ops.update and has_form:
                imports.append(
                    f"import {model.name}EditPage from './pages/{plural_kebab}/[id]/edit';"
                )
                routes.append(
                    f"  {{ path: '/{plural_kebab}/:id/edit', element: <{model.name}EditPage /> }},"
                )

        # Add auth routes if enabled
        if auth_enabled:
            routes.insert(0, "  { path: '/login', element: <Login /> },")
            routes.insert(1, "  { path: '/signup', element: <Signup /> },")
            idx = 2
            if auth_config.password_reset:
                routes.insert(
                    idx,
                    "  { path: '/forgot-password', element: <ForgotPasswordForm /> },",
                )
                idx += 1
                routes.insert(idx, "  { path: '/reset-password', element: <ResetPassword /> },")
                idx += 1
            if auth_config.email_verification:
                routes.insert(idx, "  { path: '/verify-email', element: <VerifyEmail /> },")
                idx += 1
            if auth_config.oauth_providers:
                routes.insert(idx, "  { path: '/auth/callback', element: <AuthCallback /> },")
                idx += 1

        imports_str = "\n".join(imports)
        routes_str = "\n".join(routes)

        # Build navigation links for the sidebar (only for models with include_in_nav=True)
        nav_links = []
        for model in models:
            # Skip models that should not appear in navigation
            if not model.frontend.include_in_nav:
                continue

            snake_name = to_snake_case(model.name)
            kebab_name = to_kebab_case(snake_name)
            plural_kebab = pluralize(kebab_name)
            nav_label = model.frontend.nav_label or pluralize(model.name)
            backtick = "`"
            nav_links.append(
                f"""          <NavLink
            to="/{plural_kebab}"
            className={{({{ isActive }}) =>
              {backtick}flex items-center gap-3 px-3 py-2 rounded-nordic text-sm font-medium transition-colors ${{
                isActive
                  ? 'bg-nordic-100 text-nordic-900'
                  : 'text-nordic-600 hover:bg-nordic-50 hover:text-nordic-900'
              }}{backtick}
            }}
          >
            <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={{1.5}} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
            </svg>
            {nav_label}
          </NavLink>"""
            )

        nav_links_str = "\n".join(nav_links)

        # Get project title and description from spec
        project_title = self.spec.effective_title
        project_initial = project_title[0].upper() if project_title else "P"
        project_description = self.spec.description or f"{project_title} - Built with Prism"

        # Auth imports if enabled
        auth_hook_import = (
            "\nimport { useAuth } from './contexts/AuthContext';" if auth_enabled else ""
        )

        # Check if dark mode is enabled
        dark_mode = self.spec.design.dark_mode

        content = self.renderer.render_file(
            "frontend/router/router.tsx.jinja2",
            context={
                "imports_str": imports_str,
                "auth_hook_import": auth_hook_import,
                "project_title": project_title,
                "project_initial": project_initial,
                "project_description": project_description,
                "auth_enabled": auth_enabled,
                "dark_mode": dark_mode,
                "nav_links_str": nav_links_str,
                "routes_str": routes_str,
            },
        )

        return GeneratedFile(
            path=self.src_path / "router.tsx",
            content=content,
            strategy=FileStrategy.MERGE,
            description="React Router configuration with protected regions",
        )

    def _generate_app(self) -> GeneratedFile:
        """Generate App.tsx with RouterProvider."""
        content = self.renderer.render_file(
            "frontend/router/App.tsx.jinja2",
            context={},
        )

        return GeneratedFile(
            path=self.src_path / "App.tsx",
            content=content,
            strategy=FileStrategy.MERGE,
            description="App component with RouterProvider and protected regions",
        )

    def _generate_main(self) -> GeneratedFile:
        """Generate main.tsx with urql Provider."""
        # Check which GraphQL client is configured
        graphql_client = "urql"
        if self.spec.models:
            graphql_client = self.spec.models[0].frontend.graphql_client

        # Check if auth is enabled
        auth_enabled = self.spec.auth.enabled

        # Choose the appropriate template based on GraphQL client
        if graphql_client == "urql":
            template_path = "frontend/router/main_urql.tsx.jinja2"
        else:  # Apollo
            template_path = "frontend/router/main_apollo.tsx.jinja2"

        content = self.renderer.render_file(
            template_path,
            context={
                "auth_enabled": auth_enabled,
            },
        )

        return GeneratedFile(
            path=self.src_path / "main.tsx",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Application entry point with GraphQL Provider",
        )


__all__ = ["RouterGenerator"]
