import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit";
import { OrderType } from "pages/checkout/hooks/types";
import { RootState } from "redux/store";
import { CartItem, RestaurantDetails, Tax } from "utils/types/appTypes";

interface LocationData {
  lat: number;
  lng: number;
  address: string;
}

export interface RoomDetailsType {
  roomNo: string;
  floorNo: string;
  guestName: string;
  note: string;
}

export interface OfficeDetailsType {
  officeNo: string;
  floorNo: string;
  note: string;
  company: string;
  contactPerson: string;
  phone: string;
}

export interface GiftDetailsType {
  receiverName: string;
  receiverPhone: string;
  message: string;
  senderName: string;
  senderPhone: string;
  senderEmail: string;
  isSecret: boolean;
}

interface DiscountData {
  value: number;
  isGift: boolean;
  isDiscount: boolean;
}

interface CartState {
  restaurant: Partial<RestaurantDetails>;
  items: CartItem[];
  tmp: unknown;
  specialRequest: string;
  location: LocationData | null;
  roomDetails: RoomDetailsType | null;
  officeDetails: OfficeDetailsType | null;
  giftDetails: GiftDetailsType | null;
  coupon: string;
  tip: string;
  tables: string[];
  estimateTime: Date;
  estimateTimeDate: Date;
  estimateTimeTime: string;
  collectionMethod: string;
  phone: string;
  paymentMethod: string;
  orderType: OrderType | "";
  useLoyaltyPoints: boolean;
  loyaltyValidationError: string | null;
  scheduledDate: string;
  discount: DiscountData;
  plateCar: string;
  pickupDate: string;
  pickupTime: string;
  pickupType: string;
}

// localStorage keys
export const CART_STORAGE_KEYS = {
  ITEMS: "fascano_cart_items",
  SPECIAL_REQUEST: "fascano_special_request",
  COUPON: "fascano_coupon",
  TIP: "fascano_tip",
  TABLES: "fascano_tables",
  LOCATION: "fascano_location",
  ROOM_DETAILS: "fascano_room_details",
  OFFICE_DETAILS: "fascano_office_details",
  GIFT_DETAILS: "fascano_gift_details",
  ESTIMATE_TIME: "fascano_estimate_time",
  ESTIMATE_TIME_DATE: "fascano_estimate_time_date",
  ESTIMATE_TIME_TIME: "fascano_estimate_time_time",
  COLLECTION_METHOD: "fascano_collection_method",
  PHONE: "fascano_phone",
  PAYMENT_METHOD: "fascano_payment_method",
  ORDER_TYPE: "fascano_order_type",
  USE_LOYALTY_POINTS: "fascano_use_loyalty_points",
  LOYALTY_VALIDATION_ERROR: "fascano_loyalty_validation_error",
  RESTAURANT: "fascano_restaurant",
  SCHEDULED_DATE: "fascano_scheduled_date",
  DISCOUNT: "fascano_discount",
  PLATE: "fascano_plate_car",
  PICKUP_DATE: "fascano_pickup_date",
  PICKUP_TIME: "fascano_pickup_time",
  PICKUP_TYPE: "fascano_pickup_type",
} as const;

// Utility functions for localStorage
const getFromLocalStorage = <T>(key: string, defaultValue: T): T => {
  if (typeof window === "undefined") return defaultValue;

  try {
    const item = localStorage.getItem(key);
    return item ? JSON.parse(item) : defaultValue;
  } catch (error) {
    console.warn(`Error reading ${key} from localStorage:`, error);
    return defaultValue;
  }
};

// Generate a unique identifier for cart items based on product ID, variant, extras, and comment
const generateUniqueId = (
  item: Omit<CartItem, "quantity" | "uniqueId">,
): string => {
  const variantStr = item.variant || "";
  const extrasStr = item.extras ? item.extras.sort().join(",") : "";
  const extrasGroupStr = item.extrasgroup
    ? item.extrasgroup.sort().join(",")
    : "";
  const commentStr = item.comment || "";

  return `${item.id}-${variantStr}-${extrasStr}-${extrasGroupStr}-${commentStr}`;
};

const initialState: CartState = {
  items: getFromLocalStorage(CART_STORAGE_KEYS.ITEMS, []),
  tmp: null,
  specialRequest: getFromLocalStorage(CART_STORAGE_KEYS.SPECIAL_REQUEST, ""),
  location: getFromLocalStorage(CART_STORAGE_KEYS.LOCATION, null),
  roomDetails: getFromLocalStorage(CART_STORAGE_KEYS.ROOM_DETAILS, null),
  officeDetails: getFromLocalStorage(CART_STORAGE_KEYS.OFFICE_DETAILS, null),
  giftDetails: getFromLocalStorage(CART_STORAGE_KEYS.GIFT_DETAILS, null),
  coupon: getFromLocalStorage(CART_STORAGE_KEYS.COUPON, ""),
  tip: getFromLocalStorage(CART_STORAGE_KEYS.TIP, ""),
  tables: getFromLocalStorage(CART_STORAGE_KEYS.TABLES, []),
  estimateTime: new Date(
    getFromLocalStorage(
      CART_STORAGE_KEYS.ESTIMATE_TIME,
      new Date().toISOString(),
    ),
  ),
  estimateTimeDate: new Date(
    getFromLocalStorage(
      CART_STORAGE_KEYS.ESTIMATE_TIME_DATE,
      new Date().toISOString(),
    ),
  ),
  estimateTimeTime: getFromLocalStorage(
    CART_STORAGE_KEYS.ESTIMATE_TIME_TIME,
    "",
  ),
  collectionMethod: getFromLocalStorage(
    CART_STORAGE_KEYS.COLLECTION_METHOD,
    "",
  ),
  phone: getFromLocalStorage(CART_STORAGE_KEYS.PHONE, ""),
  paymentMethod: getFromLocalStorage(CART_STORAGE_KEYS.PAYMENT_METHOD, ""),
  orderType: getFromLocalStorage(
    CART_STORAGE_KEYS.ORDER_TYPE,
    "" as OrderType | "",
  ),
  useLoyaltyPoints: getFromLocalStorage(
    CART_STORAGE_KEYS.USE_LOYALTY_POINTS,
    false,
  ),
  loyaltyValidationError: getFromLocalStorage(
    CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR,
    null,
  ),
  restaurant: getFromLocalStorage(CART_STORAGE_KEYS.RESTAURANT, { taxes: [] }),
  scheduledDate: getFromLocalStorage(CART_STORAGE_KEYS.SCHEDULED_DATE, ""),
  discount: getFromLocalStorage(CART_STORAGE_KEYS.DISCOUNT, {
    value: 0,
    isGift: false,
    isDiscount: false,
  }),
  plateCar: getFromLocalStorage(CART_STORAGE_KEYS.PLATE, ""),
  pickupDate: getFromLocalStorage(CART_STORAGE_KEYS.PICKUP_DATE, ""),
  pickupTime: getFromLocalStorage(CART_STORAGE_KEYS.PICKUP_TIME, ""),
  pickupType: getFromLocalStorage(CART_STORAGE_KEYS.PICKUP_TYPE, ""),
};

const orderSlice = createSlice({
  name: "order",
  initialState,
  reducers: {
    reset() {
      return initialState;
    },
    updateRestaurant(state, action: PayloadAction<Partial<RestaurantDetails>>) {
      state.restaurant = action.payload;
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.RESTAURANT,
          JSON.stringify(state.restaurant),
        );
      }
    },
    addItem(
      state,
      action: PayloadAction<{
        item: Omit<CartItem, "quantity">;
        quantity: number;
      }>,
    ) {
      const { item, quantity } = action.payload;

      // Generate a unique ID for this item configuration
      const uniqueId = generateUniqueId(item);

      // Check if an item with the same configuration already exists
      const existingItem = state.items.find((i) => i.uniqueId === uniqueId);

      if (existingItem) {
        // Update quantity of existing item with same configuration
        state.items = state.items.map((i) =>
          i.uniqueId === uniqueId
            ? { ...i, quantity: i.quantity + quantity }
            : i,
        );
      } else {
        // Add new item with its unique identifier
        state.items = [...state.items, { ...item, quantity, uniqueId }];
      }

      // Validate loyalty points if enabled
      if (state.useLoyaltyPoints) {
        const loyaltyItems = state.items.filter((item) => item.isHasLoyalty);
        if (loyaltyItems.length === 0) {
          state.loyaltyValidationError = "cart.noLoyaltyItemsInCart";
        } else {
          state.loyaltyValidationError = null;
        }
      }

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.ITEMS,
          JSON.stringify(state.items),
        );
        localStorage.setItem(
          CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR,
          JSON.stringify(state.loyaltyValidationError),
        );
      }
    },
    updateQuantity(
      state,
      action: PayloadAction<{
        id: number | string;
        uniqueId: string;
        quantity: number;
      }>,
    ) {
      const { uniqueId, quantity } = action.payload;
      state.items = state.items.map((item) =>
        item.uniqueId === uniqueId ? { ...item, quantity } : item,
      );

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.ITEMS,
          JSON.stringify(state.items),
        );
      }
    },
    removeItem(state, action: PayloadAction<string>) {
      state.items = state.items.filter(
        (item) => item.uniqueId !== action.payload,
      );

      // Validate loyalty points if enabled
      if (state.useLoyaltyPoints) {
        const loyaltyItems = state.items.filter((item) => item.isHasLoyalty);
        if (loyaltyItems.length === 0) {
          state.loyaltyValidationError = "cart.noLoyaltyItemsInCart";
        } else {
          state.loyaltyValidationError = null;
        }
      }

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.ITEMS,
          JSON.stringify(state.items),
        );
        localStorage.setItem(
          CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR,
          JSON.stringify(state.loyaltyValidationError),
        );
      }
    },
    clearCart(state) {
      state.items = [];
      state.specialRequest = "";
      state.phone = "";
      state.coupon = "";
      state.tip = "";
      state.tables = [];
      state.location = null;
      state.roomDetails = null;
      state.officeDetails = null;
      state.giftDetails = null;
      state.estimateTime = new Date();
      state.estimateTimeDate = new Date();
      state.estimateTimeTime = "";
      state.collectionMethod = "";
      state.paymentMethod = "";
      state.loyaltyValidationError = null;
      // Clear all cart data from localStorage
      if (typeof window !== "undefined") {
        Object.values(CART_STORAGE_KEYS)
          .filter((key) => key !== CART_STORAGE_KEYS.ORDER_TYPE)
          .forEach((key) => {
            localStorage.removeItem(key);
          });
      }
    },
    updateSpecialRequest(state, action: PayloadAction<string>) {
      state.specialRequest = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.SPECIAL_REQUEST,
          JSON.stringify(state.specialRequest),
        );
      }
    },
    clearSpecialRequest(state) {
      state.specialRequest = "";

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.removeItem(CART_STORAGE_KEYS.SPECIAL_REQUEST);
      }
    },
    updateCoupon(state, action: PayloadAction<string>) {
      state.coupon = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.COUPON,
          JSON.stringify(state.coupon),
        );
      }
    },
    updateTip(state, action: PayloadAction<string>) {
      state.tip = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(CART_STORAGE_KEYS.TIP, JSON.stringify(state.tip));
      }
    },
    updateTables(state, action: PayloadAction<string[]>) {
      state.tables = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.TABLES,
          JSON.stringify(state.tables),
        );
      }
    },
    removeTable(state) {
      state.tables = [];

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.removeItem(CART_STORAGE_KEYS.TABLES);
      }
    },
    setTmp(state, action: PayloadAction<unknown>) {
      state.tmp = action.payload;
    },
    updateLocation(state, action: PayloadAction<LocationData | null>) {
      state.location = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.LOCATION,
          JSON.stringify(state.location),
        );
      }
    },
    clearLocation(state) {
      state.location = null;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.removeItem(CART_STORAGE_KEYS.LOCATION);
      }
    },
    updateRoomDetails(state, action: PayloadAction<RoomDetailsType | null>) {
      state.roomDetails = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.ROOM_DETAILS,
          JSON.stringify(state.roomDetails),
        );
      }
    },
    updateOfficeDetails(
      state,
      action: PayloadAction<OfficeDetailsType | null>,
    ) {
      state.officeDetails = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.OFFICE_DETAILS,
          JSON.stringify(state.officeDetails),
        );
      }
    },
    updateGiftDetails(state, action: PayloadAction<GiftDetailsType | null>) {
      state.giftDetails = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.GIFT_DETAILS,
          JSON.stringify(state.giftDetails),
        );
      }
    },
    updateEstimateTime(
      state,
      action: PayloadAction<{ date: Date; time: string }>,
    ) {
      state.estimateTime = action.payload.date;
      state.estimateTimeDate = action.payload.date;
      state.estimateTimeTime = action.payload.time;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.ESTIMATE_TIME,
          JSON.stringify(state.estimateTime.toISOString()),
        );
        localStorage.setItem(
          CART_STORAGE_KEYS.ESTIMATE_TIME_DATE,
          JSON.stringify(state.estimateTimeDate.toISOString()),
        );
        localStorage.setItem(
          CART_STORAGE_KEYS.ESTIMATE_TIME_TIME,
          JSON.stringify(state.estimateTimeTime),
        );
      }
    },
    updateCollectionMethod(state, action: PayloadAction<string>) {
      state.collectionMethod = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.COLLECTION_METHOD,
          JSON.stringify(state.collectionMethod),
        );
      }
    },
    updatePhone(state, action: PayloadAction<string>) {
      state.phone = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.PHONE,
          JSON.stringify(state.phone),
        );
      }
    },
    updatePaymentMethod(state, action: PayloadAction<string>) {
      state.paymentMethod = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.PAYMENT_METHOD,
          JSON.stringify(state.paymentMethod),
        );
      }
    },
    updatePlateCar(state, action: PayloadAction<string>) {
      state.plateCar = action.payload;

      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.PLATE,
          JSON.stringify(state.plateCar),
        );
      }
    },
    updateOrderType(state, action: PayloadAction<OrderType>) {
      state.orderType = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.ORDER_TYPE,
          JSON.stringify(state.orderType),
        );
      }
    },
    updateUseLoyaltyPoints(state, action: PayloadAction<boolean>) {
      state.useLoyaltyPoints = action.payload;

      // Validate loyalty points usage
      if (action.payload) {
        const loyaltyItems = state.items.filter((item) => item.isHasLoyalty);
        if (loyaltyItems.length === 0) {
          state.loyaltyValidationError = "cart.noLoyaltyItemsInCart";
        } else {
          state.loyaltyValidationError = null;
        }
      } else {
        state.loyaltyValidationError = null;
      }

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.USE_LOYALTY_POINTS,
          JSON.stringify(state.useLoyaltyPoints),
        );
        localStorage.setItem(
          CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR,
          JSON.stringify(state.loyaltyValidationError),
        );
      }
    },
    validateLoyaltyPoints(state) {
      if (state.useLoyaltyPoints) {
        const loyaltyItems = state.items.filter((item) => item.isHasLoyalty);
        if (loyaltyItems.length === 0) {
          state.loyaltyValidationError = "cart.noLoyaltyItemsInCart";
        } else {
          state.loyaltyValidationError = null;
        }
      } else {
        state.loyaltyValidationError = null;
      }

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR,
          JSON.stringify(state.loyaltyValidationError),
        );
      }
    },
    clearLoyaltyValidationError(state) {
      state.loyaltyValidationError = null;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR,
          JSON.stringify(state.loyaltyValidationError),
        );
      }
    },
    updateScheduledDate(state, action: PayloadAction<string>) {
      state.scheduledDate = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.SCHEDULED_DATE,
          JSON.stringify(state.scheduledDate),
        );
      }
    },
    updateDiscount(state, action: PayloadAction<DiscountData>) {
      state.discount = action.payload;

      // Sync to localStorage
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.DISCOUNT,
          JSON.stringify(state.discount),
        );
      }
    },
    updatePickupDate(state, action: PayloadAction<string>) {
      state.pickupDate = action.payload;
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.PICKUP_DATE,
          JSON.stringify(state.pickupDate),
        );
      }
    },
    updatePickupTime(state, action: PayloadAction<string>) {
      state.pickupTime = action.payload;
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.PICKUP_TIME,
          JSON.stringify(state.pickupTime),
        );
      }
    },
    updatePickUpType(state, action: PayloadAction<string>) {
      state.pickupType = action.payload;
      if (typeof window !== "undefined") {
        localStorage.setItem(
          CART_STORAGE_KEYS.PICKUP_TYPE,
          JSON.stringify(state.pickupType),
        );
      }
    },
  },
});

export const {
  addItem,
  updateQuantity,
  removeItem,
  clearCart,
  updateSpecialRequest,
  clearSpecialRequest,
  updateCoupon,
  updateTip,
  updateTables,
  removeTable,
  setTmp,
  updateLocation,
  clearLocation,
  updateRoomDetails,
  updateOfficeDetails,
  updateGiftDetails,
  updateEstimateTime,
  updateCollectionMethod,
  updatePhone,
  updatePaymentMethod,
  updatePlateCar,
  updateOrderType,
  updateUseLoyaltyPoints,
  validateLoyaltyPoints,
  clearLoyaltyValidationError,
  reset,
  updateRestaurant,
  updateScheduledDate,
  updateDiscount,
  updatePickupDate,
  updatePickupTime,
  updatePickUpType,
} = orderSlice.actions;

// Tax calculation helper functions
const calculateTaxAmount = (
  state: RootState,
  amount: number,
  tax: Tax,
): number => {
  const percentage = parseFloat(tax.percentage);
  return (((state.order.restaurant?.vat || 0) + percentage) * amount) / 100;
};

const calculateTotalTax = (
  state: RootState,
  subtotal: number,
  taxes: Tax[],
): number => {
  return taxes
    .filter((tax) => tax.is_active === 1)
    .reduce(
      (total, tax) => total + calculateTaxAmount(state, subtotal, tax),
      0,
    );
};

// Selectors
export const selectCart = (state: RootState) => state.order;
export const selectCartItems = (state: RootState) => state.order.items;

export const selectCartTotal = (state: RootState) =>
  state.order.items.reduce(
    // (total, item) => total + item.price * item.quantity,
    (total, item) => {
      const itemTotalPrice = item.price * item.quantity;
      return total + itemTotalPrice;
    },
    0,
  );

export const selectCartItemsQuantity =
  (uniqueId: string) => (state: RootState) => {
    const item = state.order.items.find((i) => i.uniqueId === uniqueId);
    return item ? item.quantity : 0;
  };

// Keep backward compatibility for components that still use id
export const selectCartItemsQuantityById =
  (id: number | string) => (state: RootState) => {
    const item = state.order.items.find((i) => i.id === id);
    return item ? item.quantity : 0;
  };

// Loyalty selectors
const selectOrderItems = (state: RootState) => state.order.items;

export const selectLoyaltyItems = createSelector([selectOrderItems], (items) =>
  items.filter((item) => item.isHasLoyalty),
);

export const selectHighestPricedLoyaltyItem = (state: RootState) => {
  const loyaltyItems = selectLoyaltyItems(state);
  if (loyaltyItems.length === 0) return null;

  return loyaltyItems.reduce((highest, current) =>
    current.price > highest.price ? current : highest,
  );
};

export const selectDiscountTotal = (state: RootState) =>
  (state.order.discount.value / 100) * selectCartTotal(state) +
  (state.order.useLoyaltyPoints &&
  state.order.restaurant?.is_loyalty_enabled === 1
    ? selectHighestPricedLoyaltyItem(state)?.price || 0
    : 0);

export const selectLoyaltyValidation = createSelector(
  [(state: RootState) => state.order.useLoyaltyPoints, selectLoyaltyItems],
  (useLoyaltyPoints, loyaltyItems) => ({
    canUseLoyaltyPoints: loyaltyItems.length > 0,
    hasLoyaltyItems: loyaltyItems.length > 0,
    loyaltyItemsCount: loyaltyItems.length,
    errorMessage:
      useLoyaltyPoints && loyaltyItems.length === 0
        ? "cart.noLoyaltyItemsInCart"
        : null,
  }),
);

// Tax selectors
export const selectTaxes = (state: RootState) => state.order.restaurant.taxes;

export const selectTaxAmount = (state: RootState) => {
  const subtotal = selectCartTotal(state) - selectDiscountTotal(state);
  const taxes = selectTaxes(state);
  return calculateTotalTax(state, subtotal, taxes || []);
};

export const selectGrandTotal = (state: RootState) => {
  const totalDiscount = selectDiscountTotal(state);
  const taxAmount = selectTaxAmount(state);
  const subtotal = selectCartTotal(state);
  const deliveryFee =
    state.order.orderType === OrderType.Delivery
      ? Number(state.order.restaurant?.delivery_fees) || 0
      : 0;

  return subtotal + taxAmount - totalDiscount + deliveryFee;
};

export default orderSlice.reducer;
