import type { Express, Request, Response } from "express";
import { createServer, type Server } from "http";
import { setupAuth } from "./auth";
import { storage } from "./storage";
import { insertMovieSchema } from "@shared/schema";
import { ZodError } from "zod";
import { fromZodError } from "zod-validation-error";

// Middleware to check if the user is authenticated
const isAuthenticated = (req: Request, res: Response, next: () => void) => {
  if (req.isAuthenticated()) {
    return next();
  }
  res.status(401).json({ message: "Unauthorized" });
};

// Middleware to check if the user is an admin
const isAdmin = (req: Request, res: Response, next: () => void) => {
  if (req.isAuthenticated() && req.user.isAdmin) {
    return next();
  }
  res.status(403).json({ message: "Forbidden: Admin access required" });
};

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

  // ===== Movie Routes =====
  
  // Get all movies
  app.get("/api/movies", async (req, res) => {
    try {
      const movies = await storage.getAllMovies();
      res.json(movies);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch movies" });
    }
  });

  // Get translated movies
  app.get("/api/movies/translated", async (req, res) => {
    try {
      const movies = await storage.getTranslatedMovies();
      res.json(movies);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch translated movies" });
    }
  });

  // Get non-translated movies
  app.get("/api/movies/non-translated", async (req, res) => {
    try {
      const movies = await storage.getNonTranslatedMovies();
      res.json(movies);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch non-translated movies" });
    }
  });

  // Get movie by ID
  app.get("/api/movies/:id", async (req, res) => {
    try {
      const movie = await storage.getMovie(parseInt(req.params.id));
      if (!movie) {
        return res.status(404).json({ message: "Movie not found" });
      }
      res.json(movie);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch movie" });
    }
  });

  // Search movies
  app.get("/api/movies/search", async (req, res) => {
    try {
      const query = req.query.q as string;
      const genre = req.query.genre as string;
      const language = req.query.language as string;
      const vjName = req.query.vj as string;
      
      const movies = await storage.searchMovies({ query, genre, language, vjName });
      res.json(movies);
    } catch (error) {
      res.status(500).json({ message: "Failed to search movies" });
    }
  });

  // ===== Admin Routes =====

  // Create a movie (admin only)
  app.post("/api/movies", isAdmin, async (req, res) => {
    try {
      const movieData = insertMovieSchema.parse(req.body);
      const movie = await storage.createMovie(movieData);
      res.status(201).json(movie);
    } catch (error) {
      if (error instanceof ZodError) {
        const validationError = fromZodError(error);
        return res.status(400).json({ message: validationError.message });
      }
      res.status(500).json({ message: "Failed to create movie" });
    }
  });

  // Update a movie (admin only)
  app.put("/api/movies/:id", isAdmin, async (req, res) => {
    try {
      const id = parseInt(req.params.id);
      const movieData = insertMovieSchema.parse(req.body);
      const movie = await storage.updateMovie(id, movieData);
      if (!movie) {
        return res.status(404).json({ message: "Movie not found" });
      }
      res.json(movie);
    } catch (error) {
      if (error instanceof ZodError) {
        const validationError = fromZodError(error);
        return res.status(400).json({ message: validationError.message });
      }
      res.status(500).json({ message: "Failed to update movie" });
    }
  });

  // Delete a movie (admin only)
  app.delete("/api/movies/:id", isAdmin, async (req, res) => {
    try {
      const id = parseInt(req.params.id);
      const success = await storage.deleteMovie(id);
      if (!success) {
        return res.status(404).json({ message: "Movie not found" });
      }
      res.status(204).send();
    } catch (error) {
      res.status(500).json({ message: "Failed to delete movie" });
    }
  });

  // Get all users (admin only)
  app.get("/api/users", isAdmin, async (req, res) => {
    try {
      const users = await storage.getAllUsers();
      // Remove password from users
      const usersWithoutPassword = users.map(user => {
        const { password, ...userWithoutPassword } = user;
        return userWithoutPassword;
      });
      res.json(usersWithoutPassword);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch users" });
    }
  });

  // Delete a user (admin only)
  app.delete("/api/users/:id", isAdmin, async (req, res) => {
    try {
      const id = parseInt(req.params.id);
      const success = await storage.deleteUser(id);
      if (!success) {
        return res.status(404).json({ message: "User not found" });
      }
      res.status(204).send();
    } catch (error) {
      res.status(500).json({ message: "Failed to delete user" });
    }
  });

  // Increment movie view count
  app.post("/api/movies/:id/view", async (req, res) => {
    try {
      const id = parseInt(req.params.id);
      const movie = await storage.incrementMovieViews(id);
      if (!movie) {
        return res.status(404).json({ message: "Movie not found" });
      }
      res.json(movie);
    } catch (error) {
      res.status(500).json({ message: "Failed to update view count" });
    }
  });

  // Increment movie download count
  app.post("/api/movies/:id/download", async (req, res) => {
    try {
      const id = parseInt(req.params.id);
      const movie = await storage.incrementMovieDownloads(id);
      if (!movie) {
        return res.status(404).json({ message: "Movie not found" });
      }
      res.json(movie);
    } catch (error) {
      res.status(500).json({ message: "Failed to update download count" });
    }
  });

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