// middlewares/validation/productAlternativeValidation.ts
import { Request, Response, NextFunction } from "express";
import { catchAsyncError } from "../../middlewares/catchAsyncError";
import ErrorHandler from "../../middlewares/error";
import Joi from "joi";

const createAlternativeSchema = Joi.object({
  product_id: Joi.string().uuid().required().messages({
    "string.guid": "Invalid product ID format",
    "any.required": "Product ID is required",
  }),
  alternative_product_id: Joi.string().uuid().required().messages({
    "string.guid": "Invalid alternative product ID format",
    "any.required": "Alternative product ID is required",
  }),
  relationship_type: Joi.string()
    .valid(
      "auto-suggested",
      "manual",
      "competitor",
      "similar",
      "better-alternative",
      "cheaper-alternative",
    )
    .default("manual"),
  match_score: Joi.number().min(0).max(1).default(0.0),
  comparison_notes: Joi.string().max(1000).optional(),
  pros: Joi.array().items(Joi.string().max(200)).optional(),
  cons: Joi.array().items(Joi.string().max(200)).optional(),
  price_comparison: Joi.string()
    .valid("cheaper", "same", "more-expensive", "unknown")
    .optional(),
}).custom((value, helpers) => {
  if (value.product_id === value.alternative_product_id) {
    return helpers.error("any.invalid", {
      message: "A product cannot be an alternative to itself",
    });
  }
  return value;
});

const updateAlternativeSchema = Joi.object({
  relationship_type: Joi.string()
    .valid(
      "auto-suggested",
      "manual",
      "competitor",
      "similar",
      "better-alternative",
      "cheaper-alternative",
    )
    .optional(),
  match_score: Joi.number().min(0).max(1).optional(),
  comparison_notes: Joi.string().max(1000).optional(),
  pros: Joi.array().items(Joi.string().max(200)).optional(),
  cons: Joi.array().items(Joi.string().max(200)).optional(),
  price_comparison: Joi.string()
    .valid("cheaper", "same", "more-expensive", "unknown")
    .optional(),
  is_user_confirmed: Joi.boolean().optional(),
  is_user_rejected: Joi.boolean().optional(),
  user_vote: Joi.string().valid("upvote", "downvote").optional(),
  upvotes: Joi.number().min(0).optional(),
  downvotes: Joi.number().min(0).optional(),
  display_order: Joi.number().min(0).optional(),
  is_featured: Joi.boolean().optional(),
  is_sponsored: Joi.boolean().optional(),
  status: Joi.string()
    .valid("active", "pending", "archived", "flagged")
    .optional(),
}).custom((value, helpers) => {
  if (value.is_user_confirmed && value.is_user_rejected) {
    return helpers.error("any.invalid", {
      message: "Cannot be both confirmed and rejected",
    });
  }
  return value;
});

const voteSchema = Joi.object({
  vote_type: Joi.string().valid("upvote", "downvote").required(),
});

const bulkUpdateSchema = Joi.object({
  alternative_ids: Joi.array()
    .items(Joi.string().uuid())
    .min(1)
    .max(100)
    .required(),
  update_data: Joi.object({
    status: Joi.string()
      .valid("active", "pending", "archived", "flagged")
      .optional(),
    is_featured: Joi.boolean().optional(),
    is_sponsored: Joi.boolean().optional(),
    relationship_type: Joi.string()
      .valid(
        "auto-suggested",
        "manual",
        "competitor",
        "similar",
        "better-alternative",
        "cheaper-alternative",
      )
      .optional(),
  }).required(),
});

export const validateCreateAlternative = catchAsyncError(
  async (req: Request, res: Response, next: NextFunction) => {
    const { error, value } = createAlternativeSchema.validate(req.body, {
      abortEarly: false,
      stripUnknown: true,
    });

    if (error) {
      const errors = error.details.map((detail) => detail.message);
      return next(new ErrorHandler(errors.join(", "), 400));
    }

    req.body = value;
    next();
  },
);

export const validateUpdateAlternative = catchAsyncError(
  async (req: Request, res: Response, next: NextFunction) => {
    const { error, value } = updateAlternativeSchema.validate(req.body, {
      abortEarly: false,
      stripUnknown: true,
    });

    if (error) {
      const errors = error.details.map((detail) => detail.message);
      return next(new ErrorHandler(errors.join(", "), 400));
    }

    req.body = value;
    next();
  },
);

export const validateVote = catchAsyncError(
  async (req: Request, res: Response, next: NextFunction) => {
    const { error, value } = voteSchema.validate(req.body, {
      abortEarly: false,
      stripUnknown: true,
    });

    if (error) {
      const errors = error.details.map((detail) => detail.message);
      return next(new ErrorHandler(errors.join(", "), 400));
    }

    req.body = value;
    next();
  },
);

export const validateBulkUpdate = catchAsyncError(
  async (req: Request, res: Response, next: NextFunction) => {
    const { error, value } = bulkUpdateSchema.validate(req.body, {
      abortEarly: false,
      stripUnknown: true,
    });

    if (error) {
      const errors = error.details.map((detail) => detail.message);
      return next(new ErrorHandler(errors.join(", "), 400));
    }

    req.body = value;
    next();
  },
);
