import { z } from 'zod';
import { Uuid, DateOnly, PositiveDecimalString } from './common';
import { CONNECTOR_TYPE, PACK_LEVEL } from '../enums';

/**
 * Public API v1 payloads (used by storers / ERPs via API key).
 * Codes are used instead of internal ids so external systems never need our UUIDs.
 */

export const ApiItemSchema = z.object({
  code: z.string().min(1).max(50),
  description: z.string().min(1).max(200),
  longDescription: z.string().max(2000).optional(),
  category: z.string().max(60).optional(),
  brand: z.string().max(60).optional(),
  storageCondition: z.enum(['AMBIENT', 'AIR_CONDITIONED', 'CHILLED', 'FROZEN', 'DEEP_FROZEN', 'HAZMAT']).default('AMBIENT'),
  rotationRule: z.enum(['FIFO', 'FEFO', 'LIFO', 'FMFO']).default('FIFO'),
  lotControlled: z.boolean().default(false),
  expiryControlled: z.boolean().default(false),
  serialControlled: z.boolean().default(false),
  shelfLifeDays: z.number().int().optional(),
  baseUom: z.string().max(10).default('EA'),
  weightKg: z.number().min(0).optional(),
  cbm: z.number().min(0).optional(),
  lengthCm: z.number().min(0).optional(),
  widthCm: z.number().min(0).optional(),
  heightCm: z.number().min(0).optional(),
  hsCode: z.string().max(20).optional(),
  barcodes: z.array(z.object({ barcode: z.string().max(60), packLevel: z.enum(PACK_LEVEL).default('EACH') })).default([]),
  packs: z
    .array(
      z.object({
        level: z.enum(PACK_LEVEL),
        uomCode: z.string().max(10),
        qtyInBase: z.number().positive(),
        barcode: z.string().max(60).optional(),
        palletTi: z.number().int().optional(),
        palletHi: z.number().int().optional(),
      }),
    )
    .default([]),
  attributes: z.record(z.unknown()).default({}),
});
export type ApiItemDto = z.infer<typeof ApiItemSchema>;

export const ApiUpsertItemsSchema = z.object({ items: z.array(ApiItemSchema).min(1).max(1000) });

export const ApiAsnSchema = z.object({
  warehouseCode: z.string().min(1).max(20),
  storerCode: z.string().max(20).optional(), // required only for tenant-level keys
  reference: z.string().min(1).max(60), // PO number (idempotency per storer)
  type: z.enum(['PURCHASE', 'RETURN', 'TRANSFER_IN', 'CROSS_DOCK']).default('PURCHASE'),
  supplierCode: z.string().max(30).optional(),
  expectedAt: z.string().datetime({ offset: true }).optional(),
  containerNo: z.string().max(40).optional(),
  containerSize: z.string().max(10).optional(),
  carrierName: z.string().max(120).optional(),
  priority: z.number().int().min(1).max(9).default(5),
  notes: z.string().max(2000).optional(),
  documents: z.array(z.object({ type: z.string(), number: z.string(), date: DateOnly.optional() })).default([]),
  lines: z
    .array(
      z.object({
        lineRef: z.string().max(60).optional(),
        itemCode: z.string().min(1).max(50),
        qty: z.number().positive(),
        packLevel: z.enum(PACK_LEVEL).default('EACH'),
        lot: z.string().max(60).optional(),
        expiryDate: DateOnly.optional(),
        unitValue: z.number().min(0).optional(),
      }),
    )
    .min(1),
});
export type ApiAsnDto = z.infer<typeof ApiAsnSchema>;

export const ApiOrderSchema = z.object({
  warehouseCode: z.string().min(1).max(20),
  storerCode: z.string().max(20).optional(),
  reference: z.string().min(1).max(60), // SO / invoice number
  type: z.enum(['SALES', 'TRANSFER_OUT', 'RETURN_TO_VENDOR', 'SAMPLE', 'DISPOSAL']).default('SALES'),
  priority: z.number().int().min(1).max(9).default(5),
  customerCode: z.string().max(30).optional(),
  shipTo: z
    .object({
      name: z.string().max(200).optional(),
      contact: z.string().max(120).optional(),
      phone: z.string().max(40).optional(),
      email: z.string().email().optional(),
      address: z.record(z.unknown()).optional(),
      deliveryLocationCode: z.string().max(40).optional(),
      instructions: z.string().max(1000).optional(),
    })
    .default({}),
  carrierName: z.string().max(120).optional(),
  requestedShipDate: DateOnly.optional(),
  dueDate: z.string().datetime({ offset: true }).optional(),
  notes: z.string().max(2000).optional(),
  lines: z
    .array(
      z.object({
        lineRef: z.string().max(60).optional(),
        itemCode: z.string().min(1).max(50),
        qty: z.number().positive(),
        packLevel: z.enum(PACK_LEVEL).default('EACH'),
        lot: z.string().max(60).optional(),
        serials: z.array(z.string().max(80)).default([]),
        minExpiryDate: DateOnly.optional(),
        unitPrice: z.number().min(0).optional(),
      }),
    )
    .min(1),
});
export type ApiOrderDto = z.infer<typeof ApiOrderSchema>;

export const ApiInventoryQuerySchema = z.object({
  warehouseCode: z.string().optional(),
  storerCode: z.string().optional(),
  itemCode: z.string().optional(),
  lot: z.string().optional(),
  status: z.string().optional(),
  groupBy: z.enum(['ITEM', 'ITEM_LOT', 'DETAIL']).default('ITEM'),
});

// ---------- Connectors / webhooks ----------
export const CreateConnectorSchema = z.object({
  storerId: Uuid.nullable().optional(),
  type: z.enum(CONNECTOR_TYPE),
  name: z.string().min(1).max(120),
  config: z.record(z.unknown()).default({}),
  active: z.boolean().default(true),
});
export const UpdateConnectorSchema = CreateConnectorSchema.partial();

export const WEBHOOK_EVENTS = [
  'asn.created', 'asn.arrived', 'asn.received', 'asn.closed', 'asn.cancelled',
  'order.created', 'order.allocated', 'order.released', 'order.picked', 'order.packed', 'order.shipped', 'order.cancelled', 'order.short_closed', 'order.short_pending',
  'inventory.adjusted', 'inventory.hold_placed', 'inventory.hold_released',
  'return.received', 'return.dispositioned',
  'invoice.issued',
  'ai.proposal.created',
] as const;
export type WebhookEvent = (typeof WEBHOOK_EVENTS)[number];

export const CreateWebhookSchema = z.object({
  storerId: Uuid.nullable().optional(),
  name: z.string().min(1).max(120),
  url: z.string().url(),
  secret: z.string().min(16).max(200).optional(), // generated when omitted
  events: z.array(z.enum(WEBHOOK_EVENTS)).min(1),
  active: z.boolean().default(true),
});
export const UpdateWebhookSchema = CreateWebhookSchema.partial();

export const MessageQuerySchema = z.object({
  direction: z.enum(['INBOUND', 'OUTBOUND']).optional(),
  status: z.string().optional(),
  messageType: z.string().optional(),
  storerId: Uuid.optional(),
  from: DateOnly.optional(),
  to: DateOnly.optional(),
});

export const IMPORT_TYPES = ['SKU', 'LOCATION', 'ASN', 'ORDER', 'SERIAL', 'CUSTOMER', 'SUPPLIER'] as const;
export const CreateImportSchema = z.object({
  type: z.enum(IMPORT_TYPES),
  warehouseId: Uuid.optional(),
  storerId: Uuid.optional(),
  dryRun: z.boolean().default(false),
});

export const QtySchema = PositiveDecimalString;
