import z from 'zod';
import { OrderTypeFeature } from '../models';
import { PriceSchema } from '@isa/common/data-access';

// TODO: [Schema Refactoring - Critical Priority] Eliminate single-item schema duplication
// Current: 12 schemas (6 batch + 6 single-item), 169 lines (Complexity: 8/10)
// Target: 6 schemas with discriminated union, ~80 lines
//
// Proposed approach:
//   1. Use z.discriminatedUnion('orderType', [...]) pattern
//   2. Remove all GetSingle*AvailabilityParamsSchema exports (lines 100-168)
//   3. Handle single-item via adapter pattern:
//      - GetAvailabilityParamsAdapter.fromShoppingCartItemToSingle()
//      - Transforms batch params → single-item at adapter layer
//   4. Keep helper type: GetSingleItemAvailabilityParams<T> (derived, not validated)
//
// Benefits:
//   - 50% reduction in schema count (12 → 6)
//   - Single source of truth for validation
//   - Better error messages from discriminated union
//   - Eliminates maintenance burden (change once, not twice)
//
// Example:
//   export const GetAvailabilityParamsSchema = z.discriminatedUnion('orderType', [
//     z.object({ orderType: z.literal(OrderType.InStore), shopId: z.coerce.number(), items: ... }),
//     z.object({ orderType: z.literal(OrderType.Pickup), shopId: z.coerce.number(), items: ... }),
//     // ... other order types
//   ]);
//
// Effort: ~3 hours | Impact: High | Risk: Low
// See: complexity-analysis.md (TypeScript Section, Issue 1)

// Base item schema - used for all availability checks
const ItemSchema = z.object({
  itemId: z.coerce.number().int().positive().describe('Unique item identifier'),
  ean: z.string().describe('European Article Number barcode'),
  price: PriceSchema.describe('Item price information').optional(),
  quantity: z.coerce
    .number()
    .int()
    .positive()
    .default(1)
    .describe('Quantity of items to check availability for'),
});

// Download items don't require quantity (always 1)
const DownloadItemSchema = z.object({
  itemId: z.coerce.number().int().positive().describe('Unique item identifier'),
  ean: z.string().describe('European Article Number barcode'),
  price: PriceSchema.describe('Item price information').optional(),
});

const ItemsSchema = z
  .array(ItemSchema)
  .min(1)
  .describe('List of items to check availability for');
const DownloadItemsSchema = z
  .array(DownloadItemSchema)
  .min(1)
  .describe('List of download items to check availability for');

// In-Store availability (Rücklage) - requires branch context
export const GetInStoreAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.InStore)
    .describe('Order type specifying in-store availability check'),
  branchId: z.coerce
    .number()
    .int()
    .positive()
    .describe('Branch identifier for in-store availability')
    .optional(),
  itemsIds: z
    .array(z.coerce.number().int().positive())
    .min(1)
    .describe('List of item identifiers to check in-store availability'),
});

// Pickup availability (Abholung) - requires branch context
export const GetPickupAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.Pickup)
    .describe('Order type specifying pickup availability check'),
  branchId: z.coerce
    .number()
    .int()
    .positive()
    .describe('Branch identifier where items will be picked up'),
  items: ItemsSchema,
});

// Standard delivery availability (Versand)
export const GetDeliveryAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.Delivery)
    .describe('Order type specifying standard delivery availability check'),
  items: ItemsSchema,
});

// DIG delivery availability (DIG-Versand) - for webshop customers
export const GetDigDeliveryAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.DigitalShipping)
    .describe(
      'Order type specifying DIG delivery availability check for webshop customers',
    ),
  items: ItemsSchema,
});

// B2B delivery availability (B2B-Versand) - uses default branch
export const GetB2bDeliveryAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.B2BShipping)
    .describe('Order type specifying B2B delivery availability check'),
  items: ItemsSchema,
});

// Download availability - quantity always 1
export const GetDownloadAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.Download)
    .describe('Order type specifying download availability check'),
  items: DownloadItemsSchema,
});

// Union of all availability param types
export const GetAvailabilityParamsSchema = z.union([
  GetInStoreAvailabilityParamsSchema,
  GetPickupAvailabilityParamsSchema,
  GetDeliveryAvailabilityParamsSchema,
  GetDigDeliveryAvailabilityParamsSchema,
  GetB2bDeliveryAvailabilityParamsSchema,
  GetDownloadAvailabilityParamsSchema,
]);

// Type exports
export type GetAvailabilityParams = z.infer<typeof GetAvailabilityParamsSchema>;
export type GetAvailabilityInputParams = z.input<
  typeof GetAvailabilityParamsSchema
>;

export type GetInStoreAvailabilityParams = z.infer<
  typeof GetInStoreAvailabilityParamsSchema
>;
export type GetPickupAvailabilityParams = z.infer<
  typeof GetPickupAvailabilityParamsSchema
>;
export type GetDeliveryAvailabilityParams = z.infer<
  typeof GetDeliveryAvailabilityParamsSchema
>;
export type GetDigDeliveryAvailabilityParams = z.infer<
  typeof GetDigDeliveryAvailabilityParamsSchema
>;
export type GetB2bDeliveryAvailabilityParams = z.infer<
  typeof GetB2bDeliveryAvailabilityParamsSchema
>;
export type GetDownloadAvailabilityParams = z.infer<
  typeof GetDownloadAvailabilityParamsSchema
>;

// ========== SINGLE-ITEM SCHEMAS (for convenience methods) ==========

// Single-item schemas use the same structure but accept a single item instead of an array
const SingleInStoreAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.InStore)
    .describe('Order type specifying in-store availability check'),
  branchId: z.coerce
    .number()
    .int()
    .positive()
    .describe('Branch identifier for in-store availability')
    .optional(),
  itemId: z
    .number()
    .int()
    .positive()
    .describe('Unique item identifier to check in-store availability'),
});

const SinglePickupAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.Pickup)
    .describe('Order type specifying pickup availability check'),
  branchId: z.coerce
    .number()
    .int()
    .positive()
    .describe('Branch identifier where item will be picked up'),
  item: ItemSchema,
});

const SingleDeliveryAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.Delivery)
    .describe('Order type specifying standard delivery availability check'),
  item: ItemSchema,
});

const SingleDigDeliveryAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.DigitalShipping)
    .describe(
      'Order type specifying DIG delivery availability check for webshop customers',
    ),
  item: ItemSchema,
});

const SingleB2bDeliveryAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.B2BShipping)
    .describe('Order type specifying B2B delivery availability check'),
  item: ItemSchema,
});

const SingleDownloadAvailabilityParamsSchema = z.object({
  orderType: z
    .literal(OrderTypeFeature.Download)
    .describe('Order type specifying download availability check'),
  item: DownloadItemSchema,
});

// Union of all single-item availability param types
export const GetSingleItemAvailabilityParamsSchema = z.union([
  SingleInStoreAvailabilityParamsSchema,
  SinglePickupAvailabilityParamsSchema,
  SingleDeliveryAvailabilityParamsSchema,
  SingleDigDeliveryAvailabilityParamsSchema,
  SingleB2bDeliveryAvailabilityParamsSchema,
  SingleDownloadAvailabilityParamsSchema,
]);

// Single-item type exports
export type GetSingleItemAvailabilityParams = z.infer<
  typeof GetSingleItemAvailabilityParamsSchema
>;
export type GetSingleItemAvailabilityInputParams = z.input<
  typeof GetSingleItemAvailabilityParamsSchema
>;

export type SingleInStoreAvailabilityParams = z.infer<
  typeof SingleInStoreAvailabilityParamsSchema
>;
export type SinglePickupAvailabilityParams = z.infer<
  typeof SinglePickupAvailabilityParamsSchema
>;
export type SingleDeliveryAvailabilityParams = z.infer<
  typeof SingleDeliveryAvailabilityParamsSchema
>;
export type SingleDigDeliveryAvailabilityParams = z.infer<
  typeof SingleDigDeliveryAvailabilityParamsSchema
>;
export type SingleB2bDeliveryAvailabilityParams = z.infer<
  typeof SingleB2bDeliveryAvailabilityParamsSchema
>;
export type SingleDownloadAvailabilityParams = z.infer<
  typeof SingleDownloadAvailabilityParamsSchema
>;
