import { z } from 'zod';
import { Uuid, DateOnly, DecimalString, NonNegativeDecimalString, PositiveDecimalString } from './common';
import { BILLING_CYCLE, STORAGE_METHOD, CONTRACT_STATUS, TARIFF_GROUP, CHARGE_UNIT, CHARGE_TRIGGER, INVOICE_STATUS } from '../enums';

export const StorageCapSchema = z.object({
  unit: z.enum(['PALLET', 'CBM']),
  cap: z.number().min(0),
  byTemperatureClass: z.record(z.number().min(0)).optional(), // { FROZEN: 320, CHILLED: 180, AMBIENT: 100 }
});

export const CreateContractSchema = z.object({
  storerId: Uuid,
  contractNumber: z.string().max(40).optional(), // auto when omitted
  name: z.string().min(1).max(200),
  currency: z.string().length(3).default('KWD'),
  billingCycle: z.enum(BILLING_CYCLE).default('MONTHLY'),
  storageMethod: z.enum(STORAGE_METHOD).default('WEEKLY_CBM_OPENING_PLUS_IN'),
  storageCap: StorageCapSchema.optional(),
  minimumMonthly: NonNegativeDecimalString.optional(),
  fixedMonthlyFee: NonNegativeDecimalString.optional(),
  paymentTermsDays: z.number().int().min(0).max(365).default(30),
  weekStartsOn: z.number().int().min(0).max(6).default(1),
  validFrom: DateOnly,
  validTo: DateOnly.optional(),
  taxRatePct: z.number().min(0).max(100).default(0),
  notes: z.string().max(2000).optional(),
});
export type CreateContractDto = z.infer<typeof CreateContractSchema>;
export const UpdateContractSchema = CreateContractSchema.omit({ storerId: true }).partial().extend({ status: z.enum(CONTRACT_STATUS).optional() });

export const TariffTierSchema = z.object({ upTo: z.number().nullable(), rate: z.number().min(0) });

export const TariffConditionsSchema = z
  .object({
    containerSize: z.enum(['20', '40', '40HC', '45', 'LCL', 'TRUCK', 'VAN', 'AIR']).optional(),
    temperatureClass: z.string().optional(),
    packLevel: z.string().optional(),
    asnType: z.string().optional(),
    orderType: z.string().optional(),
    taskType: z.string().optional(),
    warehouseId: Uuid.optional(),
    minQty: z.number().optional(),
  })
  .partial();
export type TariffConditions = z.infer<typeof TariffConditionsSchema>;

export const CreateTariffSchema = z.object({
  code: z.string().trim().min(1).max(30).regex(/^[A-Z0-9_\-]+$/),
  group: z.enum(TARIFF_GROUP),
  description: z.string().min(1).max(200),
  chargeUnit: z.enum(CHARGE_UNIT),
  rate: NonNegativeDecimalString,
  minimumCharge: NonNegativeDecimalString.optional(),
  tiers: z.array(TariffTierSchema).optional(),
  trigger: z.enum(CHARGE_TRIGGER).default('MANUAL'),
  conditions: TariffConditionsSchema.default({}),
  taxable: z.boolean().default(true),
  validFrom: DateOnly.optional(),
  validTo: DateOnly.optional(),
  active: z.boolean().default(true),
  sortOrder: z.number().int().default(100),
});
export type CreateTariffDto = z.infer<typeof CreateTariffSchema>;
export const UpdateTariffSchema = CreateTariffSchema.partial();

export const CreateManualChargeSchema = z.object({
  storerId: Uuid,
  warehouseId: Uuid,
  tariffId: Uuid,
  quantity: PositiveDecimalString,
  rate: NonNegativeDecimalString.optional(), // override
  description: z.string().max(200).optional(),
  chargeDate: DateOnly,
  refType: z.enum(['ASN', 'ORDER', 'LOAD', 'TASK', 'MANUAL']).default('MANUAL'),
  refId: Uuid.optional(),
  refNumber: z.string().max(40).optional(),
  detail: z.record(z.unknown()).default({}),
});
export type CreateManualChargeDto = z.infer<typeof CreateManualChargeSchema>;

export const ChargeQuerySchema = z.object({
  storerId: Uuid.optional(),
  warehouseId: Uuid.optional(),
  status: z.string().optional(),
  periodKey: z.string().optional(),
  from: DateOnly.optional(),
  to: DateOnly.optional(),
  group: z.enum(TARIFF_GROUP).optional(),
});

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

/** Generate a draft invoice for a storer for a period. Storage is computed from snapshots; other charges from charge events. */
export const RunInvoiceSchema = z.object({
  storerId: Uuid,
  contractId: Uuid.optional(),
  periodStart: DateOnly,
  periodEnd: DateOnly,
  includePendingCharges: z.boolean().default(true),
  computeStorage: z.boolean().default(true),
  warehouseIds: z.array(Uuid).optional(),
  notes: z.string().max(2000).optional(),
});
export type RunInvoiceDto = z.infer<typeof RunInvoiceSchema>;

export const InvoiceQuerySchema = z.object({
  storerId: Uuid.optional(),
  status: z.enum(INVOICE_STATUS).optional(),
  from: DateOnly.optional(),
  to: DateOnly.optional(),
});

export const IssueInvoiceSchema = z.object({ dueAt: DateOnly.optional(), sendTo: z.array(z.string().email()).optional() });
export const RecordPaymentSchema = z.object({ amount: PositiveDecimalString, paidAt: DateOnly.optional(), reference: z.string().max(80).optional() });
export const CreateCreditNoteSchema = z.object({ amount: PositiveDecimalString, reason: z.string().min(1).max(500) });

export const StorageReportQuerySchema = z.object({
  storerId: Uuid,
  warehouseId: Uuid.optional(),
  from: DateOnly,
  to: DateOnly,
  granularity: z.enum(['DAY', 'WEEK']).default('WEEK'),
});

export const AmountSchema = DecimalString;
