import { z } from "zod";
import { paginationModel } from "../../../core/pagination.utils";
import { encodeCursor } from "../../../core/string.utils";
import { customerInfoModel } from "../../customerinfo/data";
import {
  paymentInfoModel,
  paymentInfoPayloadModel,
} from "../../paymentinfo/data/entities";
import { productModel } from "../../product/data";

export enum OrderCreationStep {
  CUSTOMER_INFO = 0,
  PAYMENT = 1,
  SUMMARY = 2,
}

export enum OrderStatus {
  PENDING_FULFILLMENT = "PENDING_FULFILLMENT",
  PARTIALLY_FULFILLED = "PARTIALLY_FULFILLED",
  FULFILLED = "FULFILLED",
  CANCELLED = "CANCELLED",
}

export const orderPriceDetailsModel = z.object({
  currency: z.string().optional(),
  discountAmount: z.coerce.number().min(0),
  basePrice: z.coerce.number().min(0),
  displayPrice: z.coerce.number().min(0),
  orderPrice: z.coerce.number().min(0),
  fullfilledPrice: z.coerce.number().min(0),
});
export type OrderPriceDetailsModel = z.infer<typeof orderPriceDetailsModel>;

export const orderModel = z.object({
  id: z.coerce.number().int().positive(),
  uid: z.string().min(1).max(32),
  status: z.nativeEnum(OrderStatus),

  ...orderPriceDetailsModel.shape,

  productId: z.number(),
  customerInfoId: z.number().nullish().optional(),
  paymentInfoId: z.number().nullish().optional(),

  createdAt: z.coerce.string(),
  updatedAt: z.coerce.string(),
});
export type OrderModel = z.infer<typeof orderModel>;

export const limitedOrderWithProductModel = orderModel
  .pick({
    id: true,
    basePrice: true,
    discountAmount: true,
    displayPrice: true,
    fullfilledPrice: true,
    status: true,
  })
  .merge(
    z.object({
      product: productModel.pick({
        id: true,
        title: true,
        description: true,
        price: true,
        discountPrice: true,
      }),
    }),
  );
export type LimitedOrderWithProductModel = z.infer<
  typeof limitedOrderWithProductModel
>;

export const fullOrderModel = orderModel.merge(
  z.object({
    product: productModel,
    customerInfo: customerInfoModel.optional().nullable(),
    paymentInfo: paymentInfoModel.optional().nullable(),
  }),
);
export type FullOrderModel = z.infer<typeof fullOrderModel>;

export const orderCursorModel = z.object({
  firstItemId: z.number(),
  lastItemId: z.number(),
  query: z.string().default(""),
});
export type OrderCursorModel = z.infer<typeof orderCursorModel>;
export function getDefaultOrderCursor() {
  return orderCursorModel.parse({ firstItemId: 0, lastItemId: 0, query: "" });
}

export const paginatedOrderInfoModel = paginationModel.merge(
  z.object({ data: z.array(orderModel) }),
);
export type PaginatedOrderInfoModel = z.infer<typeof paginatedOrderInfoModel>;
export function getDefaultPaginatedOrderInfoModel(): PaginatedOrderInfoModel {
  return {
    data: [],
    cursor: encodeCursor<OrderCursorModel>(getDefaultOrderCursor()),
    limit: 20,
    asc: true,
    totalItemCount: 0,
    totalPages: 0,
    page: 0,
  };
}

export const newOrderModel = orderModel
  .pick({
    basePrice: true,
    displayPrice: true,
    discountAmount: true,
    orderPrice: true,
    fullfilledPrice: true,
    productId: true,
    customerInfoId: true,
    paymentInfoId: true,
  })
  .extend({
    currency: z.string().optional().default("USD"),
    customerInfoId: z.number().optional(),
    paymentInfoId: z.number().optional(),
  });
export type NewOrderModel = z.infer<typeof newOrderModel>;

export const createOrderPayloadModel = z.object({
  product: productModel.optional(),
  productId: z.number().optional(),
  customerInfo: customerInfoModel,
  paymentInfo: paymentInfoPayloadModel.optional(),
  orderModel: newOrderModel,
  flowId: z.string().optional(),
});
export type CreateOrderModel = z.infer<typeof createOrderPayloadModel>;
