# ============================================================================
# RATIONALBLOKS MCP - FRONTEND CLIENT
# ============================================================================
# Copyright 2026 RationalBloks. All Rights Reserved.
#
# Client for frontend generation operations.
# Provides granular methods for each generation task.
# All file operations use encoding='utf-8' for Windows compatibility.
# ============================================================================

import json
import re
import subprocess
import shutil
from pathlib import Path
from typing import Any

from ..backend.client import LogicBlokClient

# Public API
__all__ = ["FrontendClient"]

# GitHub template repository
TEMPLATE_REPO = "https://github.com/velosovictor/rationalbloksfront.git"
TEMPLATE_BRANCH = "main"


class FrontendClient:
    """Client for frontend generation operations.
    
    Provides granular methods for:
    - Type generation
    - API service generation
    - View generation (list and form)
    - Dashboard generation
    - Route and navbar updates
    - Full scaffold
    """
    
    def __init__(self, api_key: str | None = None) -> None:
        self.api_key = api_key
        self._backend_client: LogicBlokClient | None = None
    
    async def close(self) -> None:
        if self._backend_client:
            await self._backend_client.close()
    
    async def __aenter__(self) -> "FrontendClient":
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
        await self.close()
    
    def _get_backend_client(self) -> LogicBlokClient:
        if not self.api_key:
            raise ValueError("API key required for backend operations")
        if not self._backend_client:
            self._backend_client = LogicBlokClient(self.api_key)
        return self._backend_client
    
    # ========================================================================
    # UTILITY METHODS
    # ========================================================================
    
    def _slugify(self, name: str) -> str:
        """Convert name to URL-safe slug."""
        slug = name.lower().replace(" ", "-")
        slug = re.sub(r"[^a-z0-9-]", "", slug)
        return slug
    
    def _pascal_case(self, name: str) -> str:
        """Convert to PascalCase."""
        return "".join(word.capitalize() for word in re.split(r"[_\s-]", name))
    
    def _camel_case(self, name: str) -> str:
        """Convert to camelCase."""
        pascal = self._pascal_case(name)
        return pascal[0].lower() + pascal[1:] if pascal else ""
    
    def _schema_type_to_ts(self, schema_type: str) -> str:
        """Convert schema type to TypeScript type."""
        mapping = {
            "string": "string",
            "text": "string",
            "integer": "number",
            "decimal": "number",
            "boolean": "boolean",
            "uuid": "string",
            "date": "string",
            "datetime": "string",
            "json": "Record<string, unknown>",
        }
        return mapping.get(schema_type, "unknown")
    
    def _get_singular(self, type_name: str) -> str:
        """Get singular form of type name."""
        if type_name.endswith("s") and len(type_name) > 1:
            return type_name[:-1]
        return type_name
    
    # ========================================================================
    # GENERATION METHODS
    # ========================================================================
    
    async def generate_types(
        self,
        project_path: str,
        schema: dict,
    ) -> dict[str, Any]:
        """Generate TypeScript types from schema."""
        project = Path(project_path).resolve()
        
        if not project.exists():
            return {"success": False, "error": f"Project not found: {project}"}
        
        types_content = '''// ============================================================================
// AUTO-GENERATED TYPES - Do not edit manually
// Generated by RationalBloks Frontend MCP
// ============================================================================

'''
        for table_name, fields in schema.items():
            type_name = self._pascal_case(table_name)
            singular = self._get_singular(type_name)
            
            # Main interface
            types_content += f"export interface {singular} {{\n"
            types_content += "  id: string;\n"
            
            for field_name, field_def in fields.items():
                if field_name.startswith("_"):  # Skip internal fields like _id
                    continue
                ts_type = self._schema_type_to_ts(field_def.get("type", "string"))
                optional = "" if field_def.get("required") else "?"
                types_content += f"  {field_name}{optional}: {ts_type};\n"
            
            types_content += "  created_at: string;\n"
            types_content += "  updated_at: string;\n"
            types_content += "}\n\n"
            
            # Create input type
            types_content += f"export interface Create{singular}Input {{\n"
            for field_name, field_def in fields.items():
                if field_name.startswith("_") or field_name == "user_id":
                    continue
                ts_type = self._schema_type_to_ts(field_def.get("type", "string"))
                optional = "" if field_def.get("required") else "?"
                types_content += f"  {field_name}{optional}: {ts_type};\n"
            types_content += "}\n\n"
            
            # Update input type
            types_content += f"export type Update{singular}Input = Partial<Create{singular}Input>;\n\n"
        
        types_file = project / "src" / "types" / "generated.ts"
        types_file.parent.mkdir(parents=True, exist_ok=True)
        types_file.write_text(types_content, encoding="utf-8")
        
        return {
            "success": True,
            "file": str(types_file),
            "entities": list(schema.keys()),
        }
    
    async def generate_api_service(
        self,
        project_path: str,
        schema: dict,
        api_url: str | None = None,
    ) -> dict[str, Any]:
        """Generate API service with CRUD operations."""
        project = Path(project_path).resolve()
        
        if not project.exists():
            return {"success": False, "error": f"Project not found: {project}"}
        
        api_content = '''// ============================================================================
// AUTO-GENERATED API SERVICE - Do not edit manually
// Generated by RationalBloks Frontend MCP
// ============================================================================

import { BaseApi } from "@rationalbloks/universalfront";

'''
        # Import types
        for table_name in schema.keys():
            singular = self._get_singular(self._pascal_case(table_name))
            api_content += f"import type {{ {singular}, Create{singular}Input, Update{singular}Input }} from '../types/generated';\n"
        
        default_url = api_url or 'http://localhost:8000'
        api_content += f'''
const API_URL = import.meta.env.VITE_DATABASE_API_URL || "{default_url}";

class AppApi extends BaseApi {{
  constructor() {{
    super(API_URL);
  }}

'''
        # Generate CRUD methods for each entity
        for table_name in schema.keys():
            type_name = self._pascal_case(table_name)
            singular = self._get_singular(type_name)
            
            api_content += f'''  // {type_name} CRUD
  async get{type_name}(): Promise<{singular}[]> {{
    return this.get<{singular}[]>("/{table_name}");
  }}

  async get{singular}(id: string): Promise<{singular}> {{
    return this.get<{singular}>(`/{table_name}/${{id}}`);
  }}

  async create{singular}(data: Create{singular}Input): Promise<{singular}> {{
    return this.post<{singular}>("/{table_name}", data);
  }}

  async update{singular}(id: string, data: Update{singular}Input): Promise<{singular}> {{
    return this.patch<{singular}>(`/{table_name}/${{id}}`, data);
  }}

  async delete{singular}(id: string): Promise<void> {{
    return this.delete(`/{table_name}/${{id}}`);
  }}

'''
        
        api_content += '''}

export const api = new AppApi();
export default api;
'''
        
        api_file = project / "src" / "services" / "appApi.ts"
        api_file.parent.mkdir(parents=True, exist_ok=True)
        api_file.write_text(api_content, encoding="utf-8")
        
        return {
            "success": True,
            "file": str(api_file),
            "methods": [f"get{self._pascal_case(t)}, create{self._get_singular(self._pascal_case(t))}, update{self._get_singular(self._pascal_case(t))}, delete{self._get_singular(self._pascal_case(t))}" for t in schema.keys()],
        }
    
    async def generate_entity_view(
        self,
        project_path: str,
        table_name: str,
        fields: dict,
    ) -> dict[str, Any]:
        """Generate a list view component for one entity."""
        project = Path(project_path).resolve()
        
        if not project.exists():
            return {"success": False, "error": f"Project not found: {project}"}
        
        type_name = self._pascal_case(table_name)
        singular = self._get_singular(type_name)
        
        # Get display columns (exclude user_id and internal fields)
        columns = []
        for field_name, field_def in fields.items():
            if field_name not in ["user_id"] and not field_name.startswith("_") and field_def.get("type") != "json":
                columns.append(field_name)
        
        # Limit to first 6 columns for table display
        display_columns = columns[:6]
        
        view_content = f'''// ============================================================================
// {type_name} List View - Auto-generated by RationalBloks Frontend MCP
// ============================================================================

import {{ useState, useEffect }} from "react";
import {{ useNavigate }} from "react-router-dom";
import {{
  Box,
  Typography,
  Button,
  Paper,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  IconButton,
  CircularProgress,
  Alert,
}} from "@mui/material";
import {{ Add, Edit, Delete }} from "@mui/icons-material";
import {{ api }} from "../../services/appApi";
import type {{ {singular} }} from "../../types/generated";

export default function {type_name}View() {{
  const navigate = useNavigate();
  const [items, setItems] = useState<{singular}[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {{
    loadData();
  }}, []);

  const loadData = async () => {{
    try {{
      setLoading(true);
      const data = await api.get{type_name}();
      setItems(data);
      setError(null);
    }} catch (err) {{
      setError("Failed to load {table_name}");
      console.error(err);
    }} finally {{
      setLoading(false);
    }}
  }};

  const handleDelete = async (id: string) => {{
    if (!confirm("Are you sure you want to delete this item?")) return;
    try {{
      await api.delete{singular}(id);
      loadData();
    }} catch (err) {{
      setError("Failed to delete item");
    }}
  }};

  if (loading) {{
    return (
      <Box display="flex" justifyContent="center" alignItems="center" minHeight="400px">
        <CircularProgress />
      </Box>
    );
  }}

  return (
    <Box>
      <Box display="flex" justifyContent="space-between" alignItems="center" mb={{3}}>
        <Typography variant="h4">{type_name}</Typography>
        <Button
          variant="contained"
          startIcon={{<Add />}}
          onClick={{() => navigate("/{table_name}/new")}}
        >
          Add New
        </Button>
      </Box>

      {{error && <Alert severity="error" sx={{{{ mb: 2 }}}}>{error}</Alert>}}

      <TableContainer component={{Paper}}>
        <Table>
          <TableHead>
            <TableRow>
'''
        
        # Add column headers
        for col in display_columns:
            header = col.replace("_", " ").title()
            view_content += f'              <TableCell>{header}</TableCell>\n'
        
        view_content += '''              <TableCell align="right">Actions</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {items.map((item) => (
              <TableRow key={item.id}>
'''
        
        # Add column values
        for col in display_columns:
            view_content += f'                <TableCell>{{String(item.{col} ?? "")}}</TableCell>\n'
        
        view_content += f'''                <TableCell align="right">
                  <IconButton onClick={{() => navigate(`/{table_name}/${{item.id}}/edit`)}}>
                    <Edit />
                  </IconButton>
                  <IconButton onClick={{() => handleDelete(item.id)}} color="error">
                    <Delete />
                  </IconButton>
                </TableCell>
              </TableRow>
            )}}
          </TableBody>
        </Table>
      </TableContainer>
    </Box>
  );
}}
'''
        
        view_file = project / "src" / "components" / "views" / f"{type_name}View.tsx"
        view_file.parent.mkdir(parents=True, exist_ok=True)
        view_file.write_text(view_content, encoding="utf-8")
        
        return {
            "success": True,
            "file": str(view_file),
            "columns": display_columns,
        }
    
    async def generate_entity_form(
        self,
        project_path: str,
        table_name: str,
        fields: dict,
    ) -> dict[str, Any]:
        """Generate a create/edit form component for one entity."""
        project = Path(project_path).resolve()
        
        if not project.exists():
            return {"success": False, "error": f"Project not found: {project}"}
        
        type_name = self._pascal_case(table_name)
        singular = self._get_singular(type_name)
        
        # Get editable fields (exclude user_id and internal fields)
        editable_fields = {k: v for k, v in fields.items() 
                          if k not in ["user_id"] and not k.startswith("_")}
        
        # Build initial state
        initial_state_parts = []
        for field_name, field_def in editable_fields.items():
            field_type = field_def.get("type", "string")
            default = field_def.get("default", "")
            if field_type == "boolean":
                default_val = "true" if default else "false"
            elif field_type == "integer":
                default_val = str(default) if default else "0"
            elif field_type == "decimal":
                default_val = str(default) if default else "0"
            else:
                default_val = f'"{default}"' if default else '""'
            initial_state_parts.append(f'    {field_name}: {default_val}')
        
        initial_state = ",\n".join(initial_state_parts)
        
        view_content = f'''// ============================================================================
// {singular} Form View - Auto-generated by RationalBloks Frontend MCP
// ============================================================================

import {{ useState, useEffect }} from "react";
import {{ useNavigate, useParams }} from "react-router-dom";
import {{
  Box,
  Typography,
  Button,
  Paper,
  TextField,
  FormControl,
  InputLabel,
  Select,
  MenuItem,
  FormControlLabel,
  Checkbox,
  CircularProgress,
  Alert,
}} from "@mui/material";
import {{ api }} from "../../services/appApi";
import type {{ Create{singular}Input }} from "../../types/generated";

export default function {singular}FormView() {{
  const navigate = useNavigate();
  const {{ id }} = useParams();
  const isEdit = Boolean(id);

  const [formData, setFormData] = useState<Create{singular}Input>({{
{initial_state}
  }});
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {{
    if (isEdit && id) {{
      loadData();
    }}
  }}, [id]);

  const loadData = async () => {{
    try {{
      setLoading(true);
      const data = await api.get{singular}(id!);
      setFormData(data);
      setError(null);
    }} catch (err) {{
      setError("Failed to load data");
    }} finally {{
      setLoading(false);
    }}
  }};

  const handleSubmit = async (e: React.FormEvent) => {{
    e.preventDefault();
    try {{
      setSaving(true);
      if (isEdit && id) {{
        await api.update{singular}(id, formData);
      }} else {{
        await api.create{singular}(formData);
      }}
      navigate("/{table_name}");
    }} catch (err) {{
      setError("Failed to save");
    }} finally {{
      setSaving(false);
    }}
  }};

  const handleChange = (field: keyof Create{singular}Input, value: unknown) => {{
    setFormData((prev) => ({{ ...prev, [field]: value }}));
  }};

  if (loading) {{
    return (
      <Box display="flex" justifyContent="center" alignItems="center" minHeight="400px">
        <CircularProgress />
      </Box>
    );
  }}

  return (
    <Box>
      <Typography variant="h4" mb={{3}}>
        {{isEdit ? "Edit" : "Create"}} {singular}
      </Typography>

      {{error && <Alert severity="error" sx={{{{ mb: 2 }}}}>{error}</Alert>}}

      <Paper sx={{{{ p: 3 }}}}>
        <form onSubmit={{handleSubmit}}>
          <Box display="flex" flexDirection="column" gap={{2}}>
'''
        
        # Generate form fields
        for field_name, field_def in editable_fields.items():
            field_type = field_def.get("type", "string")
            label = field_name.replace("_", " ").title()
            required = field_def.get("required", False)
            enum_values = field_def.get("enum", [])
            
            if enum_values:
                # Select dropdown for enum
                options = "\n".join([f'              <MenuItem value="{v}">{v.replace("_", " ").title()}</MenuItem>' for v in enum_values])
                view_content += f'''            <FormControl fullWidth>
              <InputLabel>{label}</InputLabel>
              <Select
                value={{formData.{field_name} || ""}}
                label="{label}"
                onChange={{(e) => handleChange("{field_name}", e.target.value)}}
                {"required" if required else ""}
              >
{options}
              </Select>
            </FormControl>
'''
            elif field_type == "boolean":
                view_content += f'''            <FormControlLabel
              control={{
                <Checkbox
                  checked={{Boolean(formData.{field_name})}}
                  onChange={{(e) => handleChange("{field_name}", e.target.checked)}}
                />
              }}
              label="{label}"
            />
'''
            elif field_type in ["integer", "decimal"]:
                view_content += f'''            <TextField
              label="{label}"
              type="number"
              value={{formData.{field_name} || ""}}
              onChange={{(e) => handleChange("{field_name}", Number(e.target.value))}}
              fullWidth
              {"required" if required else ""}
            />
'''
            elif field_type == "text":
                view_content += f'''            <TextField
              label="{label}"
              value={{formData.{field_name} || ""}}
              onChange={{(e) => handleChange("{field_name}", e.target.value)}}
              fullWidth
              multiline
              rows={{4}}
              {"required" if required else ""}
            />
'''
            elif field_type in ["date", "datetime"]:
                input_type = "date" if field_type == "date" else "datetime-local"
                view_content += f'''            <TextField
              label="{label}"
              type="{input_type}"
              value={{formData.{field_name} || ""}}
              onChange={{(e) => handleChange("{field_name}", e.target.value)}}
              fullWidth
              InputLabelProps={{{{ shrink: true }}}}
              {"required" if required else ""}
            />
'''
            else:
                # Default text field
                view_content += f'''            <TextField
              label="{label}"
              value={{formData.{field_name} || ""}}
              onChange={{(e) => handleChange("{field_name}", e.target.value)}}
              fullWidth
              {"required" if required else ""}
            />
'''
        
        view_content += f'''
            <Box display="flex" gap={{2}} mt={{2}}>
              <Button type="submit" variant="contained" disabled={{saving}}>
                {{saving ? "Saving..." : isEdit ? "Update" : "Create"}}
              </Button>
              <Button variant="outlined" onClick={{() => navigate("/{table_name}")}}>
                Cancel
              </Button>
            </Box>
          </Box>
        </form>
      </Paper>
    </Box>
  );
}}
'''
        
        form_file = project / "src" / "components" / "views" / f"{singular}FormView.tsx"
        form_file.parent.mkdir(parents=True, exist_ok=True)
        form_file.write_text(view_content, encoding="utf-8")
        
        return {
            "success": True,
            "file": str(form_file),
            "fields": list(editable_fields.keys()),
        }
    
    async def generate_all_views(
        self,
        project_path: str,
        schema: dict,
    ) -> dict[str, Any]:
        """Generate all views for all entities."""
        results = {"success": True, "files": [], "errors": []}
        
        for table_name, fields in schema.items():
            # Generate list view
            view_result = await self.generate_entity_view(project_path, table_name, fields)
            if view_result["success"]:
                results["files"].append(view_result["file"])
            else:
                results["errors"].append(f"{table_name} view: {view_result.get('error')}")
            
            # Generate form view
            form_result = await self.generate_entity_form(project_path, table_name, fields)
            if form_result["success"]:
                results["files"].append(form_result["file"])
            else:
                results["errors"].append(f"{table_name} form: {form_result.get('error')}")
        
        if results["errors"]:
            results["success"] = False
        
        return results
    
    async def generate_dashboard(
        self,
        project_path: str,
        app_name: str,
        schema: dict,
    ) -> dict[str, Any]:
        """Generate dashboard view."""
        project = Path(project_path).resolve()
        
        if not project.exists():
            return {"success": False, "error": f"Project not found: {project}"}
        
        # Build stats cards
        stats_cards = []
        for table_name in schema.keys():
            type_name = self._pascal_case(table_name)
            label = type_name.replace("_", " ")
            stats_cards.append({"name": table_name, "type": type_name, "label": label})
        
        view_content = f'''// ============================================================================
// Dashboard View - Auto-generated by RationalBloks Frontend MCP
// ============================================================================

import {{ useState, useEffect }} from "react";
import {{ useNavigate }} from "react-router-dom";
import {{
  Box,
  Typography,
  Grid,
  Card,
  CardContent,
  CardActionArea,
  CircularProgress,
}} from "@mui/material";
import {{ api }} from "../../services/appApi";

export default function DashboardView() {{
  const navigate = useNavigate();
  const [stats, setStats] = useState<Record<string, number>>({{}}); 
  const [loading, setLoading] = useState(true);

  useEffect(() => {{
    loadStats();
  }}, []);

  const loadStats = async () => {{
    try {{
      const results: Record<string, number> = {{}};
'''
        
        # Add API calls for each entity
        for card in stats_cards:
            card_name = card["name"]
            card_type = card["type"]
            view_content += f'''      try {{
        const {card_name}Data = await api.get{card_type}();
        results["{card_name}"] = {card_name}Data.length;
      }} catch (_e) {{ results["{card_name}"] = 0; }}
'''
        
        view_content += f'''      setStats(results);
    }} finally {{
      setLoading(false);
    }}
  }};

  if (loading) {{
    return (
      <Box display="flex" justifyContent="center" alignItems="center" minHeight="400px">
        <CircularProgress />
      </Box>
    );
  }}

  return (
    <Box>
      <Typography variant="h4" mb={{3}}>
        Welcome to {app_name}!
      </Typography>

      <Grid container spacing={{3}}>
'''
        
        # Add stat cards
        for card in stats_cards:
            card_name = card["name"]
            card_label = card["label"]
            view_content += f'''        <Grid item xs={{12}} sm={{6}} md={{4}} lg={{3}}>
          <Card>
            <CardActionArea onClick={{() => navigate("/{card_name}")}}>
              <CardContent>
                <Typography variant="h3" color="primary">
                  {{stats["{card_name}"] || 0}}
                </Typography>
                <Typography color="text.secondary">
                  {card_label}
                </Typography>
              </CardContent>
            </CardActionArea>
          </Card>
        </Grid>
'''
        
        view_content += '''      </Grid>
    </Box>
  );
}
'''
        
        dashboard_file = project / "src" / "components" / "views" / "DashboardView.tsx"
        dashboard_file.parent.mkdir(parents=True, exist_ok=True)
        dashboard_file.write_text(view_content, encoding="utf-8")
        
        return {
            "success": True,
            "file": str(dashboard_file),
            "stats": [c["name"] for c in stats_cards],
        }
    
    async def update_routes(
        self,
        project_path: str,
        schema: dict,
    ) -> dict[str, Any]:
        """Update App.tsx with routes for all views."""
        project = Path(project_path).resolve()
        
        if not project.exists():
            return {"success": False, "error": f"Project not found: {project}"}
        
        # Build imports and routes
        imports = ['import DashboardView from "./components/views/DashboardView";']
        routes = ['          <Route path="/dashboard" element={<DashboardView />} />']
        
        for table_name in schema.keys():
            type_name = self._pascal_case(table_name)
            singular = self._get_singular(type_name)
            
            imports.append(f'import {type_name}View from "./components/views/{type_name}View";')
            imports.append(f'import {singular}FormView from "./components/views/{singular}FormView";')
            
            routes.append(f'          <Route path="/{table_name}" element={{<{type_name}View />}} />')
            routes.append(f'          <Route path="/{table_name}/new" element={{<{singular}FormView />}} />')
            routes.append(f'          <Route path="/{table_name}/:id/edit" element={{<{singular}FormView />}} />')
        
        import_section = "\n".join(imports)
        route_section = "\n".join(routes)
        
        # Create new App.tsx
        app_content = f'''// ============================================================================
// App.tsx - Auto-generated by RationalBloks Frontend MCP
// ============================================================================

import {{ BrowserRouter, Routes, Route, Navigate }} from "react-router-dom";
import {{ ThemeProvider, CssBaseline, Box }} from "@mui/material";
import {{ GoogleOAuthProvider }} from "@react-oauth/google";
import {{ createAppProvider }} from "@rationalbloks/universalfront";

import createAppTheme from "./theme/createAppTheme";
import Navbar from "./components/shared/Navbar";
import "./styles/globals.css";

// Generated view imports
{import_section}

const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID || "";
const theme = createAppTheme();

// Create auth provider from universalfront
const {{ AuthProvider, useAuth }} = createAppProvider({{
  apiBaseUrl: import.meta.env.VITE_BUSINESS_LOGIC_API_URL || "https://logicblok.rationalbloks.com",
}});

function AppContent() {{
  const {{ isAuthenticated, isLoading }} = useAuth();

  if (isLoading) {{
    return <Box display="flex" justifyContent="center" alignItems="center" minHeight="100vh">Loading...</Box>;
  }}

  return (
    <Box sx={{{{ display: "flex", flexDirection: "column", minHeight: "100vh" }}}}>
      <Navbar />
      <Box component="main" sx={{{{ flexGrow: 1, p: 3 }}}}>
        <Routes>
          {{/* Public routes */}}
          <Route path="/" element={{isAuthenticated ? <Navigate to="/dashboard" /> : <Navigate to="/login" />}} />
          
          {{/* Protected routes */}}
{route_section}
          
          {{/* Fallback */}}
          <Route path="*" element={{<Navigate to="/dashboard" />}} />
        </Routes>
      </Box>
    </Box>
  );
}}

export default function App() {{
  return (
    <GoogleOAuthProvider clientId={{GOOGLE_CLIENT_ID}}>
      <ThemeProvider theme={{theme}}>
        <CssBaseline />
        <BrowserRouter>
          <AuthProvider>
            <AppContent />
          </AuthProvider>
        </BrowserRouter>
      </ThemeProvider>
    </GoogleOAuthProvider>
  );
}}
'''
        
        app_file = project / "src" / "App.tsx"
        app_file.write_text(app_content, encoding="utf-8")
        
        return {
            "success": True,
            "file": str(app_file),
            "routes": [f"/{t}" for t in schema.keys()] + ["/dashboard"],
        }
    
    async def update_navbar(
        self,
        project_path: str,
        app_name: str,
        schema: dict,
    ) -> dict[str, Any]:
        """Update navbar configuration."""
        project = Path(project_path).resolve()
        
        if not project.exists():
            return {"success": False, "error": f"Project not found: {project}"}
        
        nav_items = [{"label": "Dashboard", "path": "/dashboard"}]
        for table_name in schema.keys():
            type_name = self._pascal_case(table_name)
            nav_items.append({"label": type_name, "path": f"/{table_name}"})
        
        config_content = f'''// ============================================================================
// Navbar Configuration - Auto-generated by RationalBloks Frontend MCP
// ============================================================================

export const APP_NAME = "{app_name}";

export interface NavItem {{
  label: string;
  path: string;
}}

export const NAV_ITEMS: NavItem[] = {json.dumps(nav_items, indent=2)};
'''
        
        navbar_config = project / "src" / "config" / "Navbar.tsx"
        navbar_config.parent.mkdir(parents=True, exist_ok=True)
        navbar_config.write_text(config_content, encoding="utf-8")
        
        return {
            "success": True,
            "file": str(navbar_config),
            "nav_items": nav_items,
        }
    
    # ========================================================================
    # SCAFFOLD METHOD
    # ========================================================================
    
    async def scaffold_frontend(
        self,
        project_path: str,
        app_name: str,
        schema: dict,
        api_url: str | None = None,
    ) -> dict[str, Any]:
        """Apply all generators to an existing project."""
        result = {
            "success": True,
            "project_path": project_path,
            "app_name": app_name,
            "steps_completed": [],
            "steps_failed": [],
            "files_generated": [],
        }
        
        # Step 1: Generate types
        try:
            types_result = await self.generate_types(project_path, schema)
            if types_result["success"]:
                result["steps_completed"].append("generate_types")
                result["files_generated"].append(types_result["file"])
            else:
                result["steps_failed"].append({"step": "generate_types", "error": types_result.get("error")})
        except Exception as e:
            result["steps_failed"].append({"step": "generate_types", "error": str(e)})
        
        # Step 2: Generate API service
        try:
            api_result = await self.generate_api_service(project_path, schema, api_url)
            if api_result["success"]:
                result["steps_completed"].append("generate_api_service")
                result["files_generated"].append(api_result["file"])
            else:
                result["steps_failed"].append({"step": "generate_api_service", "error": api_result.get("error")})
        except Exception as e:
            result["steps_failed"].append({"step": "generate_api_service", "error": str(e)})
        
        # Step 3: Generate all views
        try:
            views_result = await self.generate_all_views(project_path, schema)
            if views_result["success"]:
                result["steps_completed"].append("generate_all_views")
                result["files_generated"].extend(views_result["files"])
            else:
                result["steps_failed"].append({"step": "generate_all_views", "error": views_result.get("errors")})
        except Exception as e:
            result["steps_failed"].append({"step": "generate_all_views", "error": str(e)})
        
        # Step 4: Generate dashboard
        try:
            dashboard_result = await self.generate_dashboard(project_path, app_name, schema)
            if dashboard_result["success"]:
                result["steps_completed"].append("generate_dashboard")
                result["files_generated"].append(dashboard_result["file"])
            else:
                result["steps_failed"].append({"step": "generate_dashboard", "error": dashboard_result.get("error")})
        except Exception as e:
            result["steps_failed"].append({"step": "generate_dashboard", "error": str(e)})
        
        # Step 5: Update routes
        try:
            routes_result = await self.update_routes(project_path, schema)
            if routes_result["success"]:
                result["steps_completed"].append("update_routes")
                result["files_generated"].append(routes_result["file"])
            else:
                result["steps_failed"].append({"step": "update_routes", "error": routes_result.get("error")})
        except Exception as e:
            result["steps_failed"].append({"step": "update_routes", "error": str(e)})
        
        # Step 6: Update navbar
        try:
            navbar_result = await self.update_navbar(project_path, app_name, schema)
            if navbar_result["success"]:
                result["steps_completed"].append("update_navbar")
                result["files_generated"].append(navbar_result["file"])
            else:
                result["steps_failed"].append({"step": "update_navbar", "error": navbar_result.get("error")})
        except Exception as e:
            result["steps_failed"].append({"step": "update_navbar", "error": str(e)})
        
        # Step 7: Configure API URL (if provided)
        if api_url:
            try:
                env_result = await self.configure_api_url(project_path, api_url)
                if env_result["success"]:
                    result["steps_completed"].append("configure_api_url")
                else:
                    result["steps_failed"].append({"step": "configure_api_url", "error": env_result.get("error")})
            except Exception as e:
                result["steps_failed"].append({"step": "configure_api_url", "error": str(e)})
        
        # Determine overall success
        critical_steps = ["generate_types", "generate_api_service", "generate_all_views", "update_routes"]
        result["success"] = all(step in result["steps_completed"] for step in critical_steps)
        
        result["next_steps"] = [
            f"cd {project_path}",
            "npm install",
            "npm run dev",
            "Open http://localhost:5173",
        ]
        
        return result
    
    # ========================================================================
    # UTILITY METHODS
    # ========================================================================
    
    async def clone_template(
        self,
        destination: str,
        project_name: str,
    ) -> dict[str, Any]:
        """Clone the template repository."""
        dest_path = Path(destination).expanduser().resolve()
        project_path = dest_path / project_name
        
        if project_path.exists():
            return {"success": False, "error": f"Directory already exists: {project_path}"}
        
        dest_path.mkdir(parents=True, exist_ok=True)
        
        try:
            result = subprocess.run(
                ["git", "clone", "--depth", "1", "--branch", TEMPLATE_BRANCH, TEMPLATE_REPO, str(project_path)],
                capture_output=True,
                text=True,
                timeout=120,
            )
            
            if result.returncode != 0:
                return {"success": False, "error": f"Git clone failed: {result.stderr}"}
            
            # Remove .git and reinitialize
            git_dir = project_path / ".git"
            if git_dir.exists():
                shutil.rmtree(git_dir)
            
            subprocess.run(["git", "init"], cwd=str(project_path), capture_output=True)
            
            return {
                "success": True,
                "project_path": str(project_path),
                "next_steps": [
                    f"Use scaffold_frontend with project_path='{project_path}'",
                    "npm install",
                    "npm run dev",
                ],
            }
            
        except subprocess.TimeoutExpired:
            return {"success": False, "error": "Git clone timed out after 120 seconds"}
        except FileNotFoundError:
            return {"success": False, "error": "Git is not installed or not in PATH"}
        except Exception as e:
            return {"success": False, "error": str(e)}
    
    async def configure_api_url(
        self,
        project_path: str,
        api_url: str,
    ) -> dict[str, Any]:
        """Configure the backend API URL in .env."""
        project = Path(project_path).expanduser().resolve()
        
        if not project.exists():
            return {"success": False, "error": f"Project not found: {project}"}
        
        env_file = project / ".env"
        env_example = project / ".env.example"
        
        # Create .env from example if needed
        if not env_file.exists() and env_example.exists():
            shutil.copy(env_example, env_file)
        elif not env_file.exists():
            env_file.write_text("", encoding="utf-8")
        
        # Read and update
        env_content = env_file.read_text(encoding="utf-8")
        lines = env_content.split("\n")
        
        updated = False
        new_lines = []
        for line in lines:
            if line.startswith("VITE_DATABASE_API_URL="):
                new_lines.append(f"VITE_DATABASE_API_URL={api_url}")
                updated = True
            else:
                new_lines.append(line)
        
        if not updated:
            new_lines.append(f"VITE_DATABASE_API_URL={api_url}")
        
        env_file.write_text("\n".join(new_lines), encoding="utf-8")
        
        return {
            "success": True,
            "env_file": str(env_file),
            "configured": {"VITE_DATABASE_API_URL": api_url},
        }
    
    async def create_backend(
        self,
        name: str,
        schema: dict,
        description: str | None = None,
    ) -> dict[str, Any]:
        """Create a backend project via the Backend MCP."""
        client = self._get_backend_client()
        return await client.create_project(name=name, schema=schema, description=description)
    
    async def get_template_structure(
        self,
        path: str = "",
        max_depth: int = 3,
    ) -> dict[str, Any]:
        """Get the file structure of the template."""
        return {
            "template": "rationalbloksfront",
            "version": "Uses @rationalbloks/universalfront npm package",
            "structure": {
                "src/": {
                    "components/": {"shared/": "Navbar, ErrorBoundary", "views/": "Page components"},
                    "config/": "App configuration",
                    "contexts/": "React contexts",
                    "services/": "API client",
                    "styles/": "Global CSS",
                    "theme/": "MUI theme",
                    "types/": "TypeScript types",
                    "App.tsx": "Main routes",
                    "main.tsx": "Entry point",
                },
                "public/": "Static assets",
                "package.json": "Dependencies",
                "vite.config.ts": "Vite config",
                ".env.example": "Environment template",
            },
            "key_dependency": "@rationalbloks/universalfront (auth, API client, utilities)",
        }
