/**
 * Optional runtime payload validation (dev/staging).
 * Enabled when CONTRACT_STRICT=true in environment.
 */
import { z } from 'zod';
import type { CommandContract, PayloadVariant } from './types.js';

function fieldSchema(field: { type: string; optional?: boolean }): z.ZodTypeAny {
  let schema: z.ZodTypeAny;
  switch (field.type) {
    case 'string':
      schema = z.string();
      break;
    case 'number':
      schema = z.number();
      break;
    case 'boolean':
      schema = z.boolean();
      break;
    case 'object':
      schema = z.record(z.string(), z.unknown());
      break;
    default:
      schema = z.unknown();
  }
  return field.optional ? schema.optional() : schema;
}

function variantSchema(variant: PayloadVariant): z.ZodTypeAny {
  switch (variant.kind) {
    case 'empty':
      return z.union([z.undefined(), z.null(), z.literal(''), z.object({}).passthrough()]);
    case 'string':
      return z.string().min(1);
    case 'number':
      return z.number();
    case 'object': {
      const shape: Record<string, z.ZodTypeAny> = {};
      for (const [key, spec] of Object.entries(variant.fields)) {
        const required = variant.required?.includes(key) ?? !spec.optional;
        shape[key] = fieldSchema({ ...spec, optional: !required });
      }
      return z.object(shape).passthrough();
    }
    default:
      return z.unknown();
  }
}

export function buildPayloadValidator(contract: CommandContract): z.ZodTypeAny {
  if (contract.payloads.length === 0) {
    return z.unknown();
  }
  return z.union(
    contract.payloads.map(variantSchema) as [z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]]
  );
}

export function validateCommandPayload(
  contract: CommandContract,
  payload: unknown
): { valid: true } | { valid: false; error: string } {
  const validator = buildPayloadValidator(contract);
  const result = validator.safeParse(payload);
  if (result.success) {
    return { valid: true };
  }
  return {
    valid: false,
    error: result.error.issues.map((i) => i.message).join('; '),
  };
}

export function isContractStrictEnabled(): boolean {
  return process.env.CONTRACT_STRICT === 'true';
}
