import { sql, type SQL } from 'drizzle-orm';
import { z } from 'zod';

export type VendorId = string & { readonly __brand: 'VendorId' };
export type DealId = string & { readonly __brand: 'DealId' };
export type UserId = string & { readonly __brand: 'UserId' };
export type OrderId = string & { readonly __brand: 'OrderId' };
export type OrderLineId = string & { readonly __brand: 'OrderLineId' };
export type CartId = string & { readonly __brand: 'CartId' };
export type VoucherId = string & { readonly __brand: 'VoucherId' };
export type SkuId = string & { readonly __brand: 'SkuId' };
export type PromoId = string & { readonly __brand: 'PromoId' };
export type ReferralId = string & { readonly __brand: 'ReferralId' };
export type PayoutId = string & { readonly __brand: 'PayoutId' };
export type StockReservationId = string & { readonly __brand: 'StockReservationId' };
export type CaseId = string & { readonly __brand: 'CaseId' };

export type BrandedId =
  | VendorId
  | DealId
  | UserId
  | OrderId
  | OrderLineId
  | CartId
  | VoucherId
  | SkuId
  | PromoId
  | ReferralId
  | PayoutId
  | StockReservationId
  | CaseId;

const uuidSchema = z.uuid();

function parseId<T extends BrandedId>(brand: string, value: string, source: string): T {
  const parsed = uuidSchema.safeParse(value);
  if (!parsed.success) {
    throw new Error(`${brand} ${source} must be a uuid`);
  }
  return parsed.data as T;
}

export const asVendorId = (value: string): VendorId => value as VendorId;
export const asDealId = (value: string): DealId => value as DealId;
export const asUserId = (value: string): UserId => value as UserId;
export const asOrderId = (value: string): OrderId => value as OrderId;
export const asOrderLineId = (value: string): OrderLineId => value as OrderLineId;
export const asCartId = (value: string): CartId => value as CartId;
export const asVoucherId = (value: string): VoucherId => value as VoucherId;
export const asSkuId = (value: string): SkuId => value as SkuId;
export const asPromoId = (value: string): PromoId => value as PromoId;
export const asReferralId = (value: string): ReferralId => value as ReferralId;
export const asPayoutId = (value: string): PayoutId => value as PayoutId;
export const asStockReservationId = (value: string): StockReservationId =>
  value as StockReservationId;
export const asCaseId = (value: string): CaseId => value as CaseId;

export const parseVendorId = (value: string): VendorId =>
  parseId<VendorId>('VendorId', value, 'value');
export const parseDealId = (value: string): DealId => parseId<DealId>('DealId', value, 'value');
export const parseUserId = (value: string): UserId => parseId<UserId>('UserId', value, 'value');
export const parseOrderId = (value: string): OrderId => parseId<OrderId>('OrderId', value, 'value');
export const parseOrderLineId = (value: string): OrderLineId =>
  parseId<OrderLineId>('OrderLineId', value, 'value');
export const parseCartId = (value: string): CartId => parseId<CartId>('CartId', value, 'value');
export const parseVoucherId = (value: string): VoucherId =>
  parseId<VoucherId>('VoucherId', value, 'value');
export const parseSkuId = (value: string): SkuId => parseId<SkuId>('SkuId', value, 'value');
export const parsePromoId = (value: string): PromoId => parseId<PromoId>('PromoId', value, 'value');
export const parseReferralId = (value: string): ReferralId =>
  parseId<ReferralId>('ReferralId', value, 'value');
export const parsePayoutId = (value: string): PayoutId =>
  parseId<PayoutId>('PayoutId', value, 'value');
export const parseStockReservationId = (value: string): StockReservationId =>
  parseId<StockReservationId>('StockReservationId', value, 'value');
export const parseCaseId = (value: string): CaseId => parseId<CaseId>('CaseId', value, 'value');

export const toModuleRef = (id: BrandedId): string => id;

export const vendorIdFromModuleRef = (ref: string): VendorId =>
  parseId<VendorId>('VendorId', ref, 'module ref');
export const dealIdFromModuleRef = (ref: string): DealId =>
  parseId<DealId>('DealId', ref, 'module ref');
export const userIdFromModuleRef = (ref: string): UserId =>
  parseId<UserId>('UserId', ref, 'module ref');
export const orderIdFromModuleRef = (ref: string): OrderId =>
  parseId<OrderId>('OrderId', ref, 'module ref');
export const orderLineIdFromModuleRef = (ref: string): OrderLineId =>
  parseId<OrderLineId>('OrderLineId', ref, 'module ref');
export const cartIdFromModuleRef = (ref: string): CartId =>
  parseId<CartId>('CartId', ref, 'module ref');
export const voucherIdFromModuleRef = (ref: string): VoucherId =>
  parseId<VoucherId>('VoucherId', ref, 'module ref');
export const skuIdFromModuleRef = (ref: string): SkuId =>
  parseId<SkuId>('SkuId', ref, 'module ref');
export const promoIdFromModuleRef = (ref: string): PromoId =>
  parseId<PromoId>('PromoId', ref, 'module ref');
export const referralIdFromModuleRef = (ref: string): ReferralId =>
  parseId<ReferralId>('ReferralId', ref, 'module ref');
export const payoutIdFromModuleRef = (ref: string): PayoutId =>
  parseId<PayoutId>('PayoutId', ref, 'module ref');
export const stockReservationIdFromModuleRef = (ref: string): StockReservationId =>
  parseId<StockReservationId>('StockReservationId', ref, 'module ref');
export const caseIdFromModuleRef = (ref: string): CaseId =>
  parseId<CaseId>('CaseId', ref, 'module ref');

export function moduleRefAsUuid(column: SQL): SQL {
  return sql`${column}::uuid`;
}
