import type { Express } from "express";
import { createServer, type Server } from "http";
import { storage } from "./storage";
import { setupAuth, isAuthenticated } from "./replitAuth";
import {
  insertPlanSchema,
  insertStepSchema,
  insertNotificationSchema,
  insertAiLogSchema,
  insertSavedAiResponseSchema,
} from "@shared/schema";
import { z } from "zod";
import { GoogleGenAI } from "@google/genai";

const genAI = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY! });

// User settings validation schema
const userSettingsSchema = z.object({
  notificationsEnabled: z.boolean().optional(),
  aiSuggestionsEnabled: z.boolean().optional(),
  timezone: z.string().optional(),
  language: z.string().optional(),
}).strict(); // Reject unknown keys

export async function registerRoutes(app: Express): Promise<Server> {
  // Setup authentication
  await setupAuth(app);

  // Auth routes
  app.get("/api/auth/user", isAuthenticated, async (req: any, res) => {
    try {
      const userId = req.user.claims.sub;
      const user = await storage.getUser(userId);
      res.json(user);
    } catch (error) {
      console.error("Error fetching user:", error);
      res.status(500).json({ message: "Failed to fetch user" });
    }
  });

  app.patch("/api/user/settings", isAuthenticated, async (req: any, res) => {
    try {
      const userId = req.user.claims.sub;
      const currentUser = await storage.getUser(userId);
      
      if (!currentUser) {
        return res.status(404).json({ message: "User not found" });
      }

      // Validate settings payload
      const validatedSettings = userSettingsSchema.parse(req.body);

      const updatedUser = await storage.upsertUser({
        ...currentUser,
        ...validatedSettings,
        id: userId,
      });
      
      res.json(updatedUser);
    } catch (error: any) {
      console.error("Error updating user settings:", error);
      if (error.name === "ZodError") {
        return res.status(400).json({ message: error.message || "Invalid settings data" });
      }
      res.status(500).json({ message: "Failed to update settings" });
    }
  });

  // Plan routes
  app.get("/api/plans", isAuthenticated, async (req: any, res) => {
    try {
      const userId = req.user.claims.sub;
      const plans = await storage.getUserPlans(userId);
      res.json(plans);
    } catch (error) {
      console.error("Error fetching plans:", error);
      res.status(500).json({ message: "Failed to fetch plans" });
    }
  });

  app.get("/api/plans/:id", isAuthenticated, async (req: any, res) => {
    try {
      const plan = await storage.getPlan(req.params.id);
      
      if (!plan) {
        return res.status(404).json({ message: "Plan not found" });
      }

      // Check if user owns the plan
      if (plan.userId !== req.user.claims.sub) {
        return res.status(403).json({ message: "Forbidden" });
      }

      res.json(plan);
    } catch (error) {
      console.error("Error fetching plan:", error);
      res.status(500).json({ message: "Failed to fetch plan" });
    }
  });

  app.post("/api/plans", isAuthenticated, async (req: any, res) => {
    try {
      const userId = req.user.claims.sub;
      const planData = insertPlanSchema.parse({
        ...req.body,
        userId,
      });

      const plan = await storage.createPlan(planData);
      res.status(201).json(plan);
    } catch (error: any) {
      console.error("Error creating plan:", error);
      res.status(400).json({ message: error.message || "Failed to create plan" });
    }
  });

  app.patch("/api/plans/:id", isAuthenticated, async (req: any, res) => {
    try {
      const plan = await storage.getPlan(req.params.id);
      
      if (!plan) {
        return res.status(404).json({ message: "Plan not found" });
      }

      if (plan.userId !== req.user.claims.sub) {
        return res.status(403).json({ message: "Forbidden" });
      }

      const updated = await storage.updatePlan(req.params.id, req.body);
      res.json(updated);
    } catch (error) {
      console.error("Error updating plan:", error);
      res.status(500).json({ message: "Failed to update plan" });
    }
  });

  app.delete("/api/plans/:id", isAuthenticated, async (req: any, res) => {
    try {
      const plan = await storage.getPlan(req.params.id);
      
      if (!plan) {
        return res.status(404).json({ message: "Plan not found" });
      }

      if (plan.userId !== req.user.claims.sub) {
        return res.status(403).json({ message: "Forbidden" });
      }

      await storage.deletePlan(req.params.id);
      res.status(204).send();
    } catch (error) {
      console.error("Error deleting plan:", error);
      res.status(500).json({ message: "Failed to delete plan" });
    }
  });

  // Step routes
  app.get("/api/plans/:planId/steps", isAuthenticated, async (req: any, res) => {
    try {
      const plan = await storage.getPlan(req.params.planId);
      
      if (!plan) {
        return res.status(404).json({ message: "Plan not found" });
      }

      if (plan.userId !== req.user.claims.sub) {
        return res.status(403).json({ message: "Forbidden" });
      }

      const steps = await storage.getPlanSteps(req.params.planId);
      res.json(steps);
    } catch (error) {
      console.error("Error fetching steps:", error);
      res.status(500).json({ message: "Failed to fetch steps" });
    }
  });

  app.post("/api/plans/:planId/steps", isAuthenticated, async (req: any, res) => {
    try {
      const plan = await storage.getPlan(req.params.planId);
      
      if (!plan) {
        return res.status(404).json({ message: "Plan not found" });
      }

      if (plan.userId !== req.user.claims.sub) {
        return res.status(403).json({ message: "Forbidden" });
      }

      const stepData = insertStepSchema.parse({
        ...req.body,
        planId: req.params.planId,
      });

      const step = await storage.createStep(stepData);
      res.status(201).json(step);
    } catch (error: any) {
      console.error("Error creating step:", error);
      res.status(400).json({ message: error.message || "Failed to create step" });
    }
  });

  app.patch("/api/steps/:id", isAuthenticated, async (req: any, res) => {
    try {
      const step = await storage.updateStep(req.params.id, req.body);
      
      if (!step) {
        return res.status(404).json({ message: "Step not found" });
      }

      res.json(step);
    } catch (error) {
      console.error("Error updating step:", error);
      res.status(500).json({ message: "Failed to update step" });
    }
  });

  app.delete("/api/steps/:id", isAuthenticated, async (req: any, res) => {
    try {
      await storage.deleteStep(req.params.id);
      res.status(204).send();
    } catch (error) {
      console.error("Error deleting step:", error);
      res.status(500).json({ message: "Failed to delete step" });
    }
  });

  // AI suggestion route
  app.post("/api/ai/suggest", isAuthenticated, async (req: any, res) => {
    try {
      const { prompt, planId } = req.body;
      const userId = req.user.claims.sub;

      if (!prompt) {
        return res.status(400).json({ message: "Prompt is required" });
      }

      const response = await genAI.models.generateContent({
        model: "gemini-2.0-flash-001",
        contents: prompt,
      });
      const suggestion = response.text || "No response generated";

      // Log AI usage
      await storage.createAiLog({
        userId,
        planId: planId || null,
        prompt,
        aiResponse: suggestion,
      });

      res.json({ suggestion });
    } catch (error) {
      console.error("Error generating AI suggestion:", error);
      res.status(500).json({ message: "Failed to generate suggestion" });
    }
  });

  // AI assistance for step route
  app.post("/api/ai/step-assist", isAuthenticated, async (req: any, res) => {
    try {
      const { stepName, userPrompt, planId } = req.body;
      const userId = req.user.claims.sub;

      if (!stepName || !userPrompt) {
        return res.status(400).json({ message: "Step name and user prompt are required" });
      }

      const fullPrompt = `Step: ${stepName}\n\nUser Query: ${userPrompt}\n\nPlease provide helpful guidance and suggestions for this task.`;

      const response = await genAI.models.generateContent({
        model: "gemini-2.5-flash",
        contents: fullPrompt,
      });
      const aiResponse = response.text || "No response generated";

      // Log AI usage
      await storage.createAiLog({
        userId,
        planId: planId || null,
        prompt: fullPrompt,
        aiResponse,
      });

      res.json({ response: aiResponse });
    } catch (error) {
      console.error("Error generating AI assistance:", error);
      res.status(500).json({ message: "Failed to generate AI assistance" });
    }
  });

  // Saved AI responses routes
  app.post("/api/saved-ai-responses", isAuthenticated, async (req: any, res) => {
    try {
      const userId = req.user.claims.sub;
      const data = insertSavedAiResponseSchema.parse({
        ...req.body,
        userId,
      });

      const savedResponse = await storage.createSavedAiResponse(data);
      res.status(201).json(savedResponse);
    } catch (error: any) {
      console.error("Error saving AI response:", error);
      res.status(400).json({ message: error.message || "Failed to save AI response" });
    }
  });

  app.get("/api/saved-ai-responses", isAuthenticated, async (req: any, res) => {
    try {
      const userId = req.user.claims.sub;
      const savedResponses = await storage.getUserSavedAiResponses(userId);
      res.json(savedResponses);
    } catch (error) {
      console.error("Error fetching saved AI responses:", error);
      res.status(500).json({ message: "Failed to fetch saved AI responses" });
    }
  });

  app.get("/api/plans/:planId/saved-ai-responses", isAuthenticated, async (req: any, res) => {
    try {
      const plan = await storage.getPlan(req.params.planId);
      
      if (!plan) {
        return res.status(404).json({ message: "Plan not found" });
      }

      if (plan.userId !== req.user.claims.sub) {
        return res.status(403).json({ message: "Forbidden" });
      }

      const savedResponses = await storage.getPlanSavedAiResponses(req.params.planId);
      res.json(savedResponses);
    } catch (error) {
      console.error("Error fetching plan saved AI responses:", error);
      res.status(500).json({ message: "Failed to fetch saved AI responses" });
    }
  });

  app.delete("/api/saved-ai-responses/:id", isAuthenticated, async (req: any, res) => {
    try {
      const userId = req.user.claims.sub;
      const savedResponses = await storage.getUserSavedAiResponses(userId);
      const response = savedResponses.find(r => r.id === req.params.id);
      
      if (!response) {
        return res.status(404).json({ message: "Saved AI response not found" });
      }
      
      await storage.deleteSavedAiResponse(req.params.id);
      res.status(204).send();
    } catch (error) {
      console.error("Error deleting saved AI response:", error);
      res.status(500).json({ message: "Failed to delete saved AI response" });
    }
  });

  // Notification routes
  app.get("/api/notifications", isAuthenticated, async (req: any, res) => {
    try {
      const userId = req.user.claims.sub;
      const notifications = await storage.getUserNotifications(userId);
      res.json(notifications);
    } catch (error) {
      console.error("Error fetching notifications:", error);
      res.status(500).json({ message: "Failed to fetch notifications" });
    }
  });

  app.patch("/api/notifications/:id/seen", isAuthenticated, async (req: any, res) => {
    try {
      await storage.markNotificationSeen(req.params.id);
      res.status(204).send();
    } catch (error) {
      console.error("Error marking notification as seen:", error);
      res.status(500).json({ message: "Failed to mark notification as seen" });
    }
  });

  app.delete("/api/notifications/:id", isAuthenticated, async (req: any, res) => {
    try {
      await storage.deleteNotification(req.params.id);
      res.status(204).send();
    } catch (error) {
      console.error("Error deleting notification:", error);
      res.status(500).json({ message: "Failed to delete notification" });
    }
  });

  // User stats route
  app.get("/api/user/stats", isAuthenticated, async (req: any, res) => {
    try {
      const userId = req.user.claims.sub;
      const plans = await storage.getUserPlans(userId);
      const aiUsageCount = await storage.getUserAiUsageCount(userId);

      const totalPlans = plans.length;
      const avgCompletion =
        plans.length > 0
          ? plans.reduce((sum, p) => sum + (p.progressPercent || 0), 0) / plans.length
          : 0;

      res.json({
        totalPlans,
        avgCompletion: Math.round(avgCompletion),
        aiUsageCount,
      });
    } catch (error) {
      console.error("Error fetching user stats:", error);
      res.status(500).json({ message: "Failed to fetch stats" });
    }
  });

  // Admin routes
  app.get("/api/admin/users", isAuthenticated, async (req: any, res) => {
    try {
      const user = await storage.getUser(req.user.claims.sub);
      
      if (!user?.isAdmin) {
        return res.status(403).json({ message: "Forbidden" });
      }

      const users = await storage.getAllUsers();
      
      // Get stats for each user
      const usersWithStats = await Promise.all(
        users.map(async (u) => {
          const plans = await storage.getUserPlans(u.id);
          const aiUsage = await storage.getUserAiUsageCount(u.id);
          const avgProgress =
            plans.length > 0
              ? plans.reduce((sum, p) => sum + (p.progressPercent || 0), 0) / plans.length
              : 0;

          return {
            ...u,
            planCount: plans.length,
            avgProgress: Math.round(avgProgress),
            aiUsage,
          };
        })
      );

      res.json(usersWithStats);
    } catch (error) {
      console.error("Error fetching admin users:", error);
      res.status(500).json({ message: "Failed to fetch users" });
    }
  });

  const httpServer = createServer(app);
  return httpServer;
}
