/**
 * Zod validators for the marketing automation surface (Task #215).
 * Mirrors the rule shapes accepted by `segments.service.normalizeRules`.
 */

import { z } from 'zod';

export const audienceRulesSchema = z.object({
  branchIds: z.array(z.string().uuid()).max(50).optional(),
  orderRecencyDays: z.number().int().positive().max(3650).optional(),
  orderCountMin: z.number().int().positive().max(10_000).optional(),
  lifetimeSpendMin: z.number().nonnegative().optional(),
  tags: z.array(z.string().min(1)).max(50).optional(),
  channel: z.enum(['any', 'email', 'whatsapp']).optional(),
  includeOptedOut: z.boolean().optional(),
}).strict();

export const createSegmentSchema = z.object({
  name: z.string().min(1).max(120),
  description: z.string().max(500).nullable().optional(),
  rules: audienceRulesSchema.default({}),
});

export const updateSegmentSchema = z.object({
  name: z.string().min(1).max(120).optional(),
  description: z.string().max(500).nullable().optional(),
  rules: audienceRulesSchema.optional(),
});

export const previewSchema = z.object({
  rules: audienceRulesSchema.default({}),
  sample: z.boolean().optional(),
});

const campaignBase = z.object({
  name: z.string().min(1).max(160),
  channel: z.enum(['email', 'whatsapp']),
  branchId: z.string().uuid().nullable().optional(),
  segmentId: z.string().uuid().nullable().optional(),
  audienceRules: audienceRulesSchema.optional(),
  subject: z.string().max(200).nullable().optional(),
  bodyHtml: z.string().max(100_000).nullable().optional(),
  templateName: z.string().max(160).nullable().optional(),
  templateLang: z.string().max(20).nullable().optional(),
  templateVars: z.array(z.string()).max(20).optional(),
  scheduledAt: z.union([z.string().datetime(), z.string().length(0)]).nullable().optional(),
  ignoreQuietHours: z.boolean().optional(),
  // Sibling-group UUID — set by the wizard when one logical broadcast is
  // fanned out into multiple per-channel campaigns (e.g. Email + WhatsApp).
  // Sibling rows share this id so the report drawer can aggregate.
  launchGroupId: z.string().uuid().nullable().optional(),
  // Per-campaign throttle controls (Task #240). Null = no per-campaign cap;
  // the dispatcher still enforces the global per-(branch,channel) cap.
  // Upper bounds are generous — anything higher is meaningless given the
  // dispatcher's batch sizes, but we still want to reject obvious garbage.
  maxPerMinute: z.number().int().positive().max(10_000).nullable().optional(),
  maxPerHour:   z.number().int().positive().max(100_000).nullable().optional(),
});

export const createCampaignSchema = campaignBase;
export const updateCampaignSchema = campaignBase.partial();

export const launchCampaignSchema = z.object({
  sendNow: z.boolean().optional(),
  scheduledAt: z.string().datetime().nullable().optional(),
});

export const optOutCustomerSchema = z.object({
  reason: z.string().max(160).optional(),
});

export type CreateSegmentInput = z.infer<typeof createSegmentSchema>;
export type UpdateSegmentInput = z.infer<typeof updateSegmentSchema>;
export type CreateCampaignInput = z.infer<typeof createCampaignSchema>;
export type UpdateCampaignInput = z.infer<typeof updateCampaignSchema>;
export type LaunchCampaignInput = z.infer<typeof launchCampaignSchema>;
export type PreviewInput = z.infer<typeof previewSchema>;
