import { z } from 'zod';
import { Uuid, DateOnly, IsoDateTime, PositiveDecimalString, NonNegativeDecimalString } from './common';
import { ASN_TYPE, ASN_STATUS, PACK_LEVEL, ITEM_CONDITION, DISCREPANCY_STATUS, DOCK_APPOINTMENT_STATUS } from '../enums';

export const AsnLineInputSchema = z.object({
  lineNo: z.number().int().min(1).optional(), // auto when omitted
  skuId: Uuid.optional(),
  skuCode: z.string().max(50).optional(), // either skuId or skuCode
  expectedQty: PositiveDecimalString, // in packLevel units if packLevel given, else base
  packLevel: z.enum(PACK_LEVEL).default('EACH'),
  expectedLot: z.string().max(60).optional(),
  expectedExpiry: DateOnly.optional(),
  externalLineRef: z.string().max(60).optional(),
  unitValue: NonNegativeDecimalString.optional(),
  notes: z.string().max(500).optional(),
}).refine((l) => l.skuId || l.skuCode, { message: 'skuId or skuCode is required' });
export type AsnLineInputDto = z.infer<typeof AsnLineInputSchema>;

export const CreateAsnSchema = z.object({
  warehouseId: Uuid,
  storerId: Uuid,
  externalRef: z.string().max(60).optional(),
  type: z.enum(ASN_TYPE).default('PURCHASE'),
  supplierId: Uuid.optional(),
  priority: z.number().int().min(1).max(9).default(5),
  expectedAt: IsoDateTime.optional(),
  carrierName: z.string().max(120).optional(),
  vehicleNo: z.string().max(40).optional(),
  containerNo: z.string().max(40).optional(),
  containerSize: z.enum(['20', '40', '40HC', '45', 'LCL', 'TRUCK', 'VAN', 'AIR']).optional(),
  sealNo: z.string().max(40).optional(),
  driverName: z.string().max(120).optional(),
  driverPhone: z.string().max(40).optional(),
  documents: z.array(z.object({ type: z.string().max(40), number: z.string().max(80), date: DateOnly.optional() })).default([]),
  notes: z.string().max(2000).optional(),
  attributes: z.record(z.unknown()).default({}),
  lines: z.array(AsnLineInputSchema).min(1),
});
export type CreateAsnDto = z.infer<typeof CreateAsnSchema>;

export const UpdateAsnSchema = CreateAsnSchema.omit({ warehouseId: true, storerId: true, lines: true }).partial().extend({
  lines: z.array(AsnLineInputSchema).optional(), // full replacement allowed while status is EXPECTED/SCHEDULED
});
export type UpdateAsnDto = z.infer<typeof UpdateAsnSchema>;

export const AsnListQuerySchema = z.object({
  warehouseId: Uuid.optional(),
  storerId: Uuid.optional(),
  status: z.enum(ASN_STATUS).optional(),
  statuses: z.string().optional(), // comma separated
  externalRef: z.string().optional(),
  expectedFrom: DateOnly.optional(),
  expectedTo: DateOnly.optional(),
});

export const ArriveAsnSchema = z.object({
  dockLocationId: Uuid.optional(),
  vehicleNo: z.string().max(40).optional(),
  sealNo: z.string().max(40).optional(),
  driverName: z.string().max(120).optional(),
  driverPhone: z.string().max(40).optional(),
  temperatureOnArrival: z.number().optional(),
  sealIntact: z.boolean().optional(),
  notes: z.string().max(1000).optional(),
});

/** One RF receiving confirmation. qty is in packLevel units; converted to base server-side. */
export const ReceiveLineSchema = z.object({
  asnLineId: Uuid.optional(), // omit for unexpected SKU
  skuId: Uuid.optional(),
  barcode: z.string().max(60).optional(), // scanned SKU/pack barcode (resolves skuId + packLevel)
  qty: PositiveDecimalString,
  packLevel: z.enum(PACK_LEVEL).optional(),
  lpnNumber: z.string().max(40).optional(), // existing or new; auto-generated when omitted and warehouse requires LPN
  locationId: Uuid.optional(), // receiving dock; defaults to ASN dock or warehouse default receiving location
  lotNumber: z.string().max(60).optional(),
  expiryDate: DateOnly.optional(),
  mfgDate: DateOnly.optional(),
  condition: z.enum(ITEM_CONDITION).default('GOOD'),
  reasonCodeId: Uuid.optional(), // required when condition != GOOD
  serials: z.array(z.string().max(80)).default([]),
  notes: z.string().max(500).optional(),
  idempotencyKey: z.string().max(100).optional(),
  allowOver: z.boolean().default(false), // supervisor override for over-receipt beyond tolerance
});
export type ReceiveLineDto = z.infer<typeof ReceiveLineSchema>;

export const ReverseReceiptSchema = z.object({ reason: z.string().min(1).max(500) });

export const CloseAsnSchema = z.object({
  sendRcr: z.boolean().default(false),
  rcrEmails: z.array(z.string().email()).optional(),
  notes: z.string().max(2000).optional(),
  forceCloseShort: z.boolean().default(false), // allow closing with open expected quantity
});
export type CloseAsnDto = z.infer<typeof CloseAsnSchema>;

export const ResolveDiscrepancySchema = z.object({
  status: z.enum(DISCREPANCY_STATUS),
  resolution: z.string().max(1000).optional(),
});

export const CreateDockAppointmentSchema = z.object({
  warehouseId: Uuid,
  dockLocationId: Uuid.optional(),
  direction: z.enum(['INBOUND', 'OUTBOUND']),
  refType: z.enum(['ASN', 'LOAD']).optional(),
  refId: Uuid.optional(),
  startsAt: IsoDateTime,
  endsAt: IsoDateTime,
  carrierName: z.string().max(120).optional(),
  vehicleNo: z.string().max(40).optional(),
  driverName: z.string().max(120).optional(),
  notes: z.string().max(1000).optional(),
});
export const UpdateDockAppointmentSchema = CreateDockAppointmentSchema.omit({ warehouseId: true }).partial().extend({
  status: z.enum(DOCK_APPOINTMENT_STATUS).optional(),
});
