import { ItemObject } from "../typings";

import { ECommerceTypes } from "../typings";
import CfExceptionHandler from "../../../core/CfExceptionHandler";
import { isISOLocal } from "../../../utils";
import { z } from "zod";

const ItemObjectSchema = z.object({
  id: z.string().min(1, "empty item id"),
  type: z.string().min(1, "invalid item type"),
  quantity: z.number().min(0, "invalid item quantity"),
  price: z.number().min(0, "invalid item price"),
  currency: z.string().min(2, "item currency required"),
  stock_status: z.string().optional(),
  promo_id: z.string().optional(),
  facility_id: z.string().optional(),
  discount: z.number().optional(),
});

const CheckoutPropertiesSchema = z
  .object({
    order_id: z.string().min(1, "empty checkout id"),
    is_successful: z.boolean(),
    cart_price: z.number().min(0, "negative checkout price"),
    items: z.array(ItemObjectSchema).min(1, "checkout empty items list"),
    cart_id: z.string().min(1, "empty checkout cart id"),
    shop_mode: z.string().optional(),
    meta: z.any().optional(),
  })
  .refine(
    (data) => {
      // Check for repeated IDs in items array
      const itemIds = data.items.map((item) => item.id);
      const uniqueIds = new Set(itemIds);
      return uniqueIds.size === itemIds.length;
    },
    {
      message: "checkout items list contains repeated ids",
      path: ["items"],
    }
  );

const CartPropertiesSchema = z.object({
  cart_id: z.string().min(1, "empty cart id"),
  action: z.string().min(1, "cart action required"),
  item: ItemObjectSchema,
  meta: z.any().optional(),
});

const ItemRequestPropertiesSchema = z.object({
  item_id: z.string().min(1, "empty request id"),
  item_name: z.string().min(1, "empty request item name"),
  manufacturer: z.string().min(1, "empty request item manufacturer"),
});

const ItemReportPropertiesSchema = z.object({
  item_id: z.string().min(1, "empty item report id"),
  item_type: z.string().min(1, "invalid item type"),
  report_id: z.string().min(1, "empty report id"),
  report_remarks: z.string().min(1, "empty report remarks"),
  store_id: z.string().min(1, "report store id required"),
  meta: z.any().optional(),
});

const CancelCheckoutPropertiesSchema = z
  .object({
    cancel_type_id: z.string().min(1, "empty cancel checkout id"),
    type: z.string().min(1, "invalid cancel type"),
    items: z.array(z.string()).min(1, "cancel checkout empty items list"),
    reason: z.string().min(1, "cancel checkout reason required"),
    meta: z.any().optional(),
  })
  .refine(
    (data) => {
      // Check for repeated IDs in items array
      const uniqueItems = new Set(data.items);
      return uniqueItems.size === data.items.length;
    },
    {
      message: "cancel checkout items contains repeated ids",
      path: ["items"],
    }
  );

const DeliveryPropertiesSchema = z
  .object({
    delivery_id: z.string().min(1, "empty delivery id"),
    order_id: z.string().min(1, "empty delivery order id"),
    is_urgent: z.boolean(),
    action: z.string().min(1, "delivery action required"),
    est_delivery_ts: z.string().optional(),
    delivery_coordinates: z
      .object({
        lat: z.number(),
        lon: z.number(),
      })
      .optional(),
    dispatch_coordinates: z
      .object({
        lat: z.number(),
        lon: z.number(),
      })
      .optional(),
    meta: z.any().optional(),
  })
  .refine(
    (data) => {
      // is_urgent must be defined (not undefined)
      return data.is_urgent !== undefined;
    },
    {
      message: "delivery is_urgent value required",
      path: ["is_urgent"],
    }
  )
  .refine(
    (data) => {
      // Validate delivery_coordinates (lat/lon cannot be 0)
      if (data.delivery_coordinates) {
        return (
          data.delivery_coordinates.lat !== 0 &&
          data.delivery_coordinates.lon !== 0
        );
      }
      return true;
    },
    {
      message: "Invalid delivery_coordinates provided",
      path: ["delivery_coordinates"],
    }
  )
  .refine(
    (data) => {
      // Validate dispatch_coordinates (lat/lon cannot be 0)
      if (data.dispatch_coordinates) {
        return (
          data.dispatch_coordinates.lat !== 0 &&
          data.dispatch_coordinates.lon !== 0
        );
      }
      return true;
    },
    {
      message: "Invalid dispatch_coordinates provided",
      path: ["dispatch_coordinates"],
    }
  )
  .refine(
    (data) => {
      // Validate date format using isISOLocal
      if (data.est_delivery_ts) {
        return isISOLocal(data.est_delivery_ts);
      }
      return true;
    },
    {
      message: "invalid delivery date format",
      path: ["est_delivery_ts"],
    }
  );

export const verifyItemObject = (
  eventName: ECommerceTypes,
  itemObject: ItemObject
) => {
  try {
    ItemObjectSchema.parse(itemObject);
    return true;
  } catch (error) {
    if (error instanceof z.ZodError) {
      // Get the first validation error message
      const firstError = error.issues[0];
      const errorMessage = firstError?.message || "validation error";

      new CfExceptionHandler().throwAndLogError(eventName, errorMessage);
    } else {
      // Fallback for unexpected errors
      new CfExceptionHandler().throwAndLogError(eventName, "validation error");
    }
    return false;
  }
};

// Event type to schema mapping
const eventSchemaMap = {
  [ECommerceTypes.Item]: {
    schema: ItemObjectSchema,
    dataExtractor: (properties: any) => properties.item,
  },
  [ECommerceTypes.Checkout]: {
    schema: CheckoutPropertiesSchema,
    dataExtractor: (properties: any) => properties,
  },
  [ECommerceTypes.Cart]: {
    schema: CartPropertiesSchema,
    dataExtractor: (properties: any) => properties,
  },
  [ECommerceTypes.ItemRequest]: {
    schema: ItemRequestPropertiesSchema,
    dataExtractor: (properties: any) => properties,
  },
  [ECommerceTypes.ItemReport]: {
    schema: ItemReportPropertiesSchema,
    dataExtractor: (properties: any) => properties,
  },
  [ECommerceTypes.Delivery]: {
    schema: DeliveryPropertiesSchema,
    dataExtractor: (properties: any) => properties,
  },
  [ECommerceTypes.CancelCheckout]: {
    schema: CancelCheckoutPropertiesSchema,
    dataExtractor: (properties: any) => properties,
  },
} as const;

// Generic validation function that handles all event types
export const validate = (
  eventType: ECommerceTypes,
  properties: any
): boolean => {
  try {
    const eventConfig = eventSchemaMap[eventType];

    if (!eventConfig) {
      new CfExceptionHandler().throwAndLogError(
        eventType,
        `Unknown event type: ${eventType}`
      );
      return false;
    }

    const { schema, dataExtractor } = eventConfig;
    const dataToValidate = dataExtractor(properties);

    // Parse the data - this will throw if validation fails
    schema.parse(dataToValidate);
    return true;
  } catch (error) {
    if (error instanceof z.ZodError) {
      // Get the first validation error message
      const firstError = error.issues[0];
      const errorMessage = firstError?.message || "validation error";

      new CfExceptionHandler().throwAndLogError(eventType, errorMessage);
    } else {
      // Fallback for unexpected errors
      new CfExceptionHandler().throwAndLogError(eventType, "validation error");
    }
    return false;
  }
};
