import { Router, Request, Response, NextFunction } from "express";
import { z } from "zod";
import { prisma } from "../lib/prisma.js";
import { requireAuth, requireRole } from "../middleware/auth.js";
import { AppError } from "../middleware/errorHandler.js";
import { parsePage, paginatedResponse } from "../lib/pagination.js";
import { AuthenticatedRequest } from "../types/index.js";

const router = Router();
const auth = requireAuth as unknown as (r: Request, s: Response, n: NextFunction) => void;
const managerUp = requireRole("owner", "manager") as unknown as (r: Request, s: Response, n: NextFunction) => void;

const ProductSchema = z.object({
  name: z.string().min(1).max(200),
  sku: z.string().max(100).optional(),
  description: z.string().max(1000).optional(),
  price: z.number().min(0),
  categoryId: z.string().optional().nullable(),
  taxId: z.string().optional().nullable(),
  tags: z.string().max(500).optional(),
});

router.get("/", auth, async (req: Request, res: Response, next: NextFunction) => {
  try {
    const authReq = req as AuthenticatedRequest;
    const { page, limit, skip } = parsePage(req.query as Record<string, unknown>);
    const { categoryId, search } = req.query as { categoryId?: string; search?: string };

    const where = {
      vendorId: authReq.auth.vendorId,
      ...(categoryId ? { categoryId } : {}),
      ...(search
        ? { name: { contains: search } }
        : {}),
    };

    const [data, total] = await Promise.all([
      prisma.product.findMany({
        where,
        skip,
        take: limit,
        orderBy: { name: "asc" },
        include: { category: true, tax: true },
      }),
      prisma.product.count({ where }),
    ]);

    res.json(paginatedResponse(data, total, { page, limit, skip }));
  } catch (err) {
    next(err);
  }
});

router.get("/:id", auth, async (req: Request, res: Response, next: NextFunction) => {
  try {
    const authReq = req as AuthenticatedRequest;
    const product = await prisma.product.findFirst({
      where: { id: req.params.id, vendorId: authReq.auth.vendorId },
      include: { category: true, tax: true },
    });
    if (!product) throw new AppError(404, "NOT_FOUND", "Product not found");
    res.json(product);
  } catch (err) {
    next(err);
  }
});

router.post("/", auth, managerUp, async (req: Request, res: Response, next: NextFunction) => {
  try {
    const authReq = req as AuthenticatedRequest;
    const body = ProductSchema.parse(req.body);
    const product = await prisma.product.create({
      data: { ...body, vendorId: authReq.auth.vendorId },
      include: { category: true, tax: true },
    });
    res.status(201).json(product);
  } catch (err) {
    next(err);
  }
});

router.put("/:id", auth, managerUp, async (req: Request, res: Response, next: NextFunction) => {
  try {
    const authReq = req as AuthenticatedRequest;
    const existing = await prisma.product.findFirst({
      where: { id: req.params.id, vendorId: authReq.auth.vendorId },
    });
    if (!existing) throw new AppError(404, "NOT_FOUND", "Product not found");

    const body = ProductSchema.parse(req.body);
    const product = await prisma.product.update({
      where: { id: req.params.id },
      data: { ...body, version: { increment: 1 } },
      include: { category: true, tax: true },
    });
    res.json(product);
  } catch (err) {
    next(err);
  }
});

router.delete("/:id", auth, managerUp, async (req: Request, res: Response, next: NextFunction) => {
  try {
    const authReq = req as AuthenticatedRequest;
    const existing = await prisma.product.findFirst({
      where: { id: req.params.id, vendorId: authReq.auth.vendorId },
    });
    if (!existing) throw new AppError(404, "NOT_FOUND", "Product not found");
    await prisma.product.delete({ where: { id: req.params.id } });
    res.status(204).send();
  } catch (err) {
    next(err);
  }
});

export default router;
