import type { Response } from "express";
import type {
  CreateProductInput,
  ProductIdParamInput,
  ProductListQueryInput,
  ProductSlugParamInput,
  UpdateProductInput,
} from "../@types/productRequests.js";
import type { AuthenticatedRequest } from "../@types/auth.js";
import { getProductFilters } from "../services/productFilters.js";
import {
  archiveProduct,
  createProduct,
  getProductById,
  getProductBySlug,
  listProducts,
  updateProduct,
} from "../services/productService.js";
import { sendError, sendSuccess } from "../utils/apiResponse.js";

const getStaffId = (req: AuthenticatedRequest) => {
  if (req.auth?.actorType !== "staff") return null;
  return req.auth.staff.id;
};

export const listPublicProducts = async (
  req: AuthenticatedRequest,
  res: Response,
) => {
  const query = req.validatedQuery as ProductListQueryInput;
  const result = await listProducts(query, { includeAllStatuses: false });
  return sendSuccess(res, 200, result);
};

export const getPublicProductFilters = async (
  _req: AuthenticatedRequest,
  res: Response,
) => {
  const result = await getProductFilters();
  return sendSuccess(res, 200, result);
};

export const getPublicProductBySlug = async (
  req: AuthenticatedRequest,
  res: Response,
) => {
  const { slug } = req.validatedParams as ProductSlugParamInput;
  const product = await getProductBySlug(slug, false);

  if (!product) {
    return sendError(res, 404, "PRODUCT_NOT_FOUND", "Product not found.");
  }

  return sendSuccess(res, 200, product);
};

export const listAdminProducts = async (
  req: AuthenticatedRequest,
  res: Response,
) => {
  const query = req.validatedQuery as ProductListQueryInput;
  const result = await listProducts(query, { includeAllStatuses: true });
  return sendSuccess(res, 200, result);
};

export const getAdminProductById = async (
  req: AuthenticatedRequest,
  res: Response,
) => {
  const { id } = req.validatedParams as ProductIdParamInput;
  const product = await getProductById(id);

  if (!product) {
    return sendError(res, 404, "PRODUCT_NOT_FOUND", "Product not found.");
  }

  return sendSuccess(res, 200, product);
};

export const createAdminProduct = async (
  req: AuthenticatedRequest,
  res: Response,
) => {
  const staffId = getStaffId(req);
  if (!staffId)
    return sendError(res, 403, "FORBIDDEN", "Staff access required.");

  try {
    const product = await createProduct(
      req.validatedBody as CreateProductInput,
      staffId,
    );
    return sendSuccess(res, 201, product, "Product created.");
  } catch (error) {
    const message =
      error instanceof Error ? error.message : "Could not create product.";
    if (message.includes("Duplicate") || message.includes("unique")) {
      return sendError(
        res,
        409,
        "PRODUCT_CONFLICT",
        "Product SKU or slug already exists.",
      );
    }
    return sendError(res, 400, "PRODUCT_CREATE_FAILED", message);
  }
};

export const updateAdminProduct = async (
  req: AuthenticatedRequest,
  res: Response,
) => {
  const staffId = getStaffId(req);
  if (!staffId)
    return sendError(res, 403, "FORBIDDEN", "Staff access required.");

  const { id } = req.validatedParams as ProductIdParamInput;

  try {
    const product = await updateProduct(
      id,
      req.validatedBody as UpdateProductInput,
      staffId,
    );
    if (!product)
      return sendError(res, 404, "PRODUCT_NOT_FOUND", "Product not found.");
    return sendSuccess(res, 200, product, "Product updated.");
  } catch (error) {
    const message =
      error instanceof Error ? error.message : "Could not update product.";
    if (message.includes("Duplicate") || message.includes("unique")) {
      return sendError(
        res,
        409,
        "PRODUCT_CONFLICT",
        "Product SKU or slug already exists.",
      );
    }
    return sendError(res, 400, "PRODUCT_UPDATE_FAILED", message);
  }
};

export const archiveAdminProduct = async (
  req: AuthenticatedRequest,
  res: Response,
) => {
  const { id } = req.validatedParams as ProductIdParamInput;
  const product = await archiveProduct(id);

  if (!product) {
    return sendError(res, 404, "PRODUCT_NOT_FOUND", "Product not found.");
  }

  return sendSuccess(res, 200, product, "Product archived.");
};
