import type { Express, Request, Response } from "express";
import { createServer, type Server } from "http";
import { storage } from "./storage";
import { insertJumpSchema, jumpQuerySchema } from "@shared/schema";
import { z } from "zod";
import { formatCsvData } from "../client/src/lib/utils";
import { ZodError } from "zod";
import { fromZodError } from "zod-validation-error";

export async function registerRoutes(app: Express): Promise<Server> {
  // Get all statistics for dashboard
  app.get("/api/stats", async (req: Request, res: Response) => {
    try {
      const stats = await storage.getStatistics();
      res.json(stats);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch statistics" });
    }
  });

  // Get all jumps (paginated, sorted, filtered)
  app.get("/api/jumps", async (req: Request, res: Response) => {
    try {
      const validatedQuery = jumpQuerySchema.parse(req.query);
      const result = await storage.getJumps(validatedQuery);
      res.json(result);
    } catch (error) {
      if (error instanceof ZodError) {
        const validationError = fromZodError(error);
        res.status(400).json({ message: validationError.message });
      } else {
        res.status(500).json({ message: "Failed to fetch jumps" });
      }
    }
  });

  // Get a single jump
  app.get("/api/jumps/:id", async (req: Request, res: Response) => {
    try {
      const id = parseInt(req.params.id);
      if (isNaN(id)) {
        res.status(400).json({ message: "Invalid jump ID" });
        return;
      }

      const jump = await storage.getJump(id);
      if (!jump) {
        res.status(404).json({ message: "Jump not found" });
        return;
      }

      res.json(jump);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch jump" });
    }
  });

  // Create a new jump
  app.post("/api/jumps", async (req: Request, res: Response) => {
    try {
      const jumpData = insertJumpSchema.parse(req.body);
      const jump = await storage.createJump(jumpData);
      res.status(201).json(jump);
    } catch (error) {
      if (error instanceof ZodError) {
        const validationError = fromZodError(error);
        res.status(400).json({ message: validationError.message });
      } else {
        res.status(500).json({ message: "Failed to create jump" });
      }
    }
  });

  // Bulk create jumps from CSV
  app.post("/api/jumps/bulk", async (req: Request, res: Response) => {
    try {
      // Validate each jump in the array
      const jumpsData = req.body;
      
      if (!Array.isArray(jumpsData) || jumpsData.length === 0) {
        res.status(400).json({ message: "Invalid data format. Expected non-empty array of jumps." });
        return;
      }
      
      // Format CSV data to match our schema
      const formattedData = formatCsvData(jumpsData);
      
      // Validate each jump
      const validatedJumps = formattedData.map(jump => insertJumpSchema.parse(jump));
      
      // Create all jumps
      const createdJumps = await storage.createJumps(validatedJumps);
      
      res.status(201).json({ 
        message: `Successfully added ${createdJumps.length} jumps`, 
        jumps: createdJumps 
      });
    } catch (error) {
      if (error instanceof ZodError) {
        const validationError = fromZodError(error);
        res.status(400).json({ message: validationError.message });
      } else {
        res.status(500).json({ message: "Failed to process CSV data" });
      }
    }
  });

  // Update a jump
  app.patch("/api/jumps/:id", async (req: Request, res: Response) => {
    try {
      const id = parseInt(req.params.id);
      if (isNaN(id)) {
        res.status(400).json({ message: "Invalid jump ID" });
        return;
      }

      // Partial validation for update
      const updateSchema = insertJumpSchema.partial();
      const jumpData = updateSchema.parse(req.body);
      
      const updatedJump = await storage.updateJump(id, jumpData);
      if (!updatedJump) {
        res.status(404).json({ message: "Jump not found" });
        return;
      }

      res.json(updatedJump);
    } catch (error) {
      if (error instanceof ZodError) {
        const validationError = fromZodError(error);
        res.status(400).json({ message: validationError.message });
      } else {
        res.status(500).json({ message: "Failed to update jump" });
      }
    }
  });

  // Delete a jump
  app.delete("/api/jumps/:id", async (req: Request, res: Response) => {
    try {
      const id = parseInt(req.params.id);
      if (isNaN(id)) {
        res.status(400).json({ message: "Invalid jump ID" });
        return;
      }

      const success = await storage.deleteJump(id);
      if (!success) {
        res.status(404).json({ message: "Jump not found" });
        return;
      }

      res.status(204).end();
    } catch (error) {
      res.status(500).json({ message: "Failed to delete jump" });
    }
  });

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