import { z } from 'zod';
import { createDealBodyShape, imageSetSchema } from './vendor';

/**
 * Draft schema — permissive variant of `createDealBodySchema`.
 *
 * Drafts are autosaved continuously while the vendor types, so all fields are
 * optional and partially-filled values must not throw. Empty strings (from
 * uncontrolled form inputs) are coerced to `undefined` before regex/datetime
 * validators run, and `windowStart`/`windowEnd` accept both full ISO with
 * offset (server-canonical) and `datetime-local` (`YYYY-MM-DDTHH:mm`, what the
 * `<input type="datetime-local">` element produces).
 *
 * Strict publish-time validation lives in `submitDraft`, which re-parses the
 * draft payload with `createDealBodySchema` directly.
 */

/** Coerce empty / whitespace-only strings to `undefined`, leave everything else untouched. */
const emptyToUndef = (v: unknown) => (typeof v === 'string' && v.trim() === '' ? undefined : v);

/** Accepts ISO with offset (`2026-01-01T15:30:00+02:00`) OR datetime-local (`2026-01-01T15:30`). */
const datetimeLocalOrIso = z.union([
  z.iso.datetime({ offset: true }),
  z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?$/),
]);

export const draftDealPayloadSchema = createDealBodyShape
  .extend({
    // Strip imageSet when it's empty or lacks a non-empty deal array.
    // Form initializes imageSet to {} before any image is uploaded → must not fail schema.
    imageSet: z.preprocess((v) => {
      if (v == null) return undefined;
      if (typeof v !== 'object' || Array.isArray(v)) return undefined;
      const obj = v as Record<string, unknown>;
      if (!Array.isArray(obj.deal) || (obj.deal as unknown[]).length === 0) return undefined;
      return v;
    }, imageSetSchema.optional()),
    title: z.preprocess(emptyToUndef, z.string().trim().max(120).optional()),
    description: z.preprocess(emptyToUndef, z.string().trim().max(2000).optional()),
    categoryId: z.preprocess(emptyToUndef, z.string().optional()),
    originalPrice: z.preprocess(
      emptyToUndef,
      z
        .string()
        .trim()
        .regex(/^\d+(\.\d{1,2})?$/, 'Price must be a positive decimal with up to 2 decimal places')
        .optional(),
    ),
    discountedPrice: z.preprocess(
      emptyToUndef,
      z
        .string()
        .trim()
        .regex(/^\d+(\.\d{1,2})?$/, 'Price must be a positive decimal with up to 2 decimal places')
        .optional(),
    ),
    windowStart: z.preprocess(emptyToUndef, datetimeLocalOrIso.optional()),
    windowEnd: z.preprocess(emptyToUndef, datetimeLocalOrIso.optional()),
    pickupStart: z.preprocess(
      emptyToUndef,
      z
        .string()
        .trim()
        .regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
        .optional(),
    ),
    pickupEnd: z.preprocess(
      emptyToUndef,
      z
        .string()
        .trim()
        .regex(/^\d{2}:\d{2}$/, 'Time must be in HH:MM format')
        .optional(),
    ),
    pickupAddress: z.preprocess(emptyToUndef, z.string().trim().max(300).optional()),
    specialInstructions: z.preprocess(emptyToUndef, z.string().trim().max(1000).optional()),
  })
  .partial()
  // Form sends additional non-server fields (groupFillRule, etc.); strip
  // them silently rather than reject the draft.
  .loose();
export type DraftDealPayload = z.infer<typeof draftDealPayloadSchema>;

export function isFullyEmpty(v: unknown): boolean {
  if (v == null || v === '') return true;
  if (Array.isArray(v)) return v.every(isFullyEmpty);
  if (typeof v === 'object') {
    const vals = Object.values(v as Record<string, unknown>);
    return vals.length === 0 || vals.every(isFullyEmpty);
  }
  return false;
}
