/**
 * Vendor Deal Draft decider — pure decision module.
 *
 * Draft state is weak (row exists or doesn't), so the decider here just
 * enforces validation invariants:
 *
 *   create_requested:  payload not empty, cap not exceeded → insert-draft
 *   update_requested:  if empty → delete; else → update-draft
 *   star_toggle:       → set-starred(!currentlyStarred)
 *   delete_requested:  → delete-draft
 *   submit_requested:  strict schema valid → atomic-submit
 *
 * Pure module: no imports from @/server/db, do-client, outbox-producer, payments, fetch.
 */

import { z } from 'zod';
import { draftDealPayloadSchema, isFullyEmpty } from '@/server/schemas/vendor-deal-draft.js';
import { createDealBodySchema } from '@/server/schemas/vendor.js';
import { qtyTiersInputSchema } from '@/server/schemas/sku-qty-tiers.js';
import type {
  VendorDealDraftEvent,
  CreateDraftRequestedEvent,
  UpdateDraftRequestedEvent,
  StarTogglePayload,
  DeleteDraftRequestedEvent,
  SubmitDraftRequestedEvent,
} from './events.js';
import type { AtomicSubmitEffect, QueryOnlyDraftEffect, VendorDealDraftEffect } from './effects.js';

export type VendorDealDraftErrorCode = 'EMPTY_DRAFT' | 'DRAFT_CAP_EXCEEDED' | 'INVALID_PAYLOAD';

export const DRAFT_CAP_NON_ACTIVE = 3;

type VendorDealDraftFailure = {
  ok: false;
  error: VendorDealDraftErrorCode;
  message: string;
  /** Populated only for INVALID_PAYLOAD on submit. */
  fieldErrors?: Record<string, string[]>;
  /** Populated only for DRAFT_CAP_EXCEEDED. */
  cap?: number;
};

export type QueryOnlyDraftDecision =
  | { ok: true; effects: QueryOnlyDraftEffect[] }
  | VendorDealDraftFailure;

export type SubmitDraftDecision =
  | { ok: true; effects: [AtomicSubmitEffect] }
  | VendorDealDraftFailure;

export type VendorDealDraftDecision =
  | { ok: true; effects: VendorDealDraftEffect[] }
  | VendorDealDraftFailure;

export function decide(event: CreateDraftRequestedEvent): QueryOnlyDraftDecision;
export function decide(event: UpdateDraftRequestedEvent): QueryOnlyDraftDecision;
export function decide(event: StarTogglePayload): QueryOnlyDraftDecision;
export function decide(event: DeleteDraftRequestedEvent): QueryOnlyDraftDecision;
export function decide(event: SubmitDraftRequestedEvent): SubmitDraftDecision;
export function decide(event: VendorDealDraftEvent): VendorDealDraftDecision;
export function decide(event: VendorDealDraftEvent): VendorDealDraftDecision {
  switch (event.kind) {
    case 'create_requested':
      return decideCreate(event);
    case 'update_requested':
      return decideUpdate(event);
    case 'star_toggle':
      return decideStar(event);
    case 'delete_requested':
      return decideDelete(event);
    case 'submit_requested':
      return decideSubmit(event);
  }
}

function deriveTitle(p: Record<string, unknown>): string | null {
  const t = p['title'];
  return typeof t === 'string' && t.trim() ? t.trim().slice(0, 120) : null;
}

function decideCreate(event: CreateDraftRequestedEvent): QueryOnlyDraftDecision {
  if (isFullyEmpty(event.payload)) {
    return {
      ok: false,
      error: 'EMPTY_DRAFT',
      message: 'Draft payload is fully empty — nothing to save.',
    };
  }
  const parsed = draftDealPayloadSchema.parse(event.payload);
  // After defaults are applied by Zod (e.g. tagIds:[], isVoucher:false), check again
  // using only the user-supplied keys, not the post-default object.
  const userSupplied =
    typeof event.payload === 'object' && event.payload !== null
      ? Object.fromEntries(
          Object.entries(event.payload as Record<string, unknown>).filter(
            ([, v]) => v !== undefined,
          ),
        )
      : {};
  if (Object.keys(userSupplied).length === 0) {
    return {
      ok: false,
      error: 'EMPTY_DRAFT',
      message: 'Draft payload is fully empty — nothing to save.',
    };
  }
  if (!event.capExempt && event.currentDraftCount >= DRAFT_CAP_NON_ACTIVE) {
    return {
      ok: false,
      error: 'DRAFT_CAP_EXCEEDED',
      message: `Draft cap of ${DRAFT_CAP_NON_ACTIVE} reached. Become ACTIVE to create more deals.`,
      cap: DRAFT_CAP_NON_ACTIVE,
    };
  }
  return {
    ok: true,
    effects: [
      {
        kind: 'insert-draft',
        vendorId: event.vendorId,
        payload: parsed as Record<string, unknown>,
        title: deriveTitle(parsed as Record<string, unknown>),
      },
    ],
  };
}

function decideUpdate(event: UpdateDraftRequestedEvent): QueryOnlyDraftDecision {
  const rawIsEmpty =
    isFullyEmpty(event.payload) ||
    (typeof event.payload === 'object' &&
      event.payload !== null &&
      Object.keys(event.payload as Record<string, unknown>).length === 0);
  if (rawIsEmpty) {
    return { ok: true, effects: [{ kind: 'delete-draft', draftId: event.draftId }] };
  }
  const parsed = draftDealPayloadSchema.parse(event.payload);
  return {
    ok: true,
    effects: [
      {
        kind: 'update-draft',
        draftId: event.draftId,
        payload: parsed as Record<string, unknown>,
        title: deriveTitle(parsed as Record<string, unknown>),
      },
    ],
  };
}

function decideStar(event: StarTogglePayload): QueryOnlyDraftDecision {
  return {
    ok: true,
    effects: [{ kind: 'set-starred', draftId: event.draftId, starred: !event.currentlyStarred }],
  };
}

function decideDelete(event: DeleteDraftRequestedEvent): QueryOnlyDraftDecision {
  return { ok: true, effects: [{ kind: 'delete-draft', draftId: event.draftId }] };
}

function decideSubmit(event: SubmitDraftRequestedEvent): SubmitDraftDecision {
  const strict = createDealBodySchema.safeParse(event.normalizedPayload);
  if (!strict.success) {
    return {
      ok: false,
      error: 'INVALID_PAYLOAD',
      message: 'Draft payload is not a valid publishable deal.',
      fieldErrors: z.flattenError(strict.error).fieldErrors as Record<string, string[]>,
    };
  }

  // Extract singleQtyTiers from the raw payload before Zod strips it.
  // The autosave payload stores this as a top-level key (buildAutosavePayload spreads all form values).
  const rawTiers = (event.normalizedPayload as Record<string, unknown>).singleQtyTiers;
  const tiersParsed = qtyTiersInputSchema.safeParse(rawTiers ?? []);
  if (!tiersParsed.success) {
    return {
      ok: false,
      error: 'INVALID_PAYLOAD',
      message: 'Invalid quantity-discount tiers in draft.',
      fieldErrors: z.flattenError(tiersParsed.error).fieldErrors as unknown as Record<
        string,
        string[]
      >,
    };
  }

  return {
    ok: true,
    effects: [
      {
        kind: 'atomic-submit',
        draftId: event.draftId,
        vendorId: event.vendorId,
        validatedDeal: strict.data as Record<string, unknown>,
        singleQtyTiers: tiersParsed.data,
      },
    ],
  };
}
