/**
 * Admin-side zod schemas for the support system API surface.
 * CONTRACT §4 — names locked.
 */

import { z } from 'zod';

// ─── GET /api/admin/support/inbox ─────────────────────────────────────────────

export const adminInboxSchema = z.object({
  type: z.enum(['ticket', 'case', 'all']).default('all'),
  status: z.string().optional(), // comma-separated status list
  slaBreach: z.enum(['breached', 'warning', 'healthy', 'any']).default('any'),
  assigned: z.enum(['me', 'unassigned', 'any']).default('any'),
  category: z.string().optional(),
  priority: z.enum(['low', 'normal', 'high', 'urgent']).optional(),
  aiConfidenceLte: z.coerce.number().min(0).max(1).optional(),
  page: z.coerce.number().int().min(1).default(1),
  pageSize: z.coerce.number().int().min(1).max(100).default(25),
  sort: z.enum(['sla_soonest', 'updated_desc', 'created_desc']).default('sla_soonest'),
});
export type AdminInboxQuery = z.infer<typeof adminInboxSchema>;

// ─── POST /api/admin/support/[type]/[id]/assign ───────────────────────────────

export const adminAssignSchema = z.object({
  assignedAgentId: z.uuid().nullable(), // null = unassign
});

// ─── POST /api/admin/support/[type]/[id]/messages ────────────────────────────

export const adminNewMessageSchema = z.object({
  text: z.string().trim().min(1).max(5000),
  visibility: z.enum(['public', 'site_internal']),
  attachmentIds: z.array(z.uuid()).max(10).default([]),
});

// ─── POST /api/admin/cases/[id]/decision ─────────────────────────────────────

export const adminCaseDecisionSchema = z.discriminatedUnion('outcome', [
  z.object({
    outcome: z.literal('refund_full'),
    amountCents: z.number().int().positive(),
    reason: z.string().trim().min(1).max(1000),
  }),
  z.object({
    outcome: z.literal('refund_partial'),
    amountCents: z.number().int().positive(),
    reason: z.string().trim().min(1).max(1000),
  }),
  z.object({
    outcome: z.literal('replacement'),
    reason: z.string().trim().min(1).max(1000),
  }),
  z.object({
    outcome: z.literal('deny'),
    reason: z.string().trim().min(1).max(1000),
  }),
  z.object({
    outcome: z.literal('reassign_vendor'),
    reason: z.string().trim().min(1).max(1000),
  }),
]);

export const adminAiOfferApprovalParamsSchema = z.object({
  id: z.uuid(),
  offerId: z.uuid(),
});

export const adminAiOfferApprovalBodySchema = z.strictObject({});

// ─── GET /api/admin/support/kb ────────────────────────────────────────────────

export const adminKbListSchema = z.object({
  locale: z.enum(['he', 'en', 'all']).default('all'),
  category: z
    .enum(['faq', 'policy', 'refund_rules', 'redemption_rules', 'internal', 'all'])
    .default('all'),
  q: z.string().trim().max(500).optional(),
  page: z.coerce.number().int().min(1).default(1),
});

// Parent fields: non-localized, same for all locales.
export const adminKbParentSchema = z.object({
  category: z.enum(['faq', 'policy', 'refund_rules', 'redemption_rules', 'internal']),
  tags: z.array(z.string().trim().min(1).max(40)).max(20).default([]),
  visibility: z.enum(['public', 'internal']).default('public'),
  isActive: z.boolean().default(true),
});
export type AdminKbParent = z.infer<typeof adminKbParentSchema>;

// Translation fields: locale-scoped content.
export const adminKbTranslationSchema = z.object({
  locale: z.enum(['he', 'en']),
  slug: z
    .string()
    .trim()
    .regex(/^[a-z0-9][a-z0-9-]*$/)
    .min(2)
    .max(120),
  title: z.string().trim().min(1).max(200),
  bodyMd: z.string().trim().min(1).max(20_000),
});
export type AdminKbTranslation = z.infer<typeof adminKbTranslationSchema>;

// Combined create payload: parent + first translation.
const _adminKbCreateSchemaInner = adminKbParentSchema.extend(adminKbTranslationSchema.shape);

export const adminKbCreateSchema = z.preprocess((raw: unknown) => {
  if (!raw || typeof raw !== 'object') return raw;
  const out: Record<string, unknown> = { ...(raw as Record<string, unknown>) };
  // Accept `body` as alias for `bodyMd`
  if (out['body'] !== undefined && out['bodyMd'] === undefined) {
    out['bodyMd'] = out['body'];
    delete out['body'];
  }
  // Map category alias: how_to → faq
  if (out['category'] === 'how_to') out['category'] = 'faq';
  // Map status → isActive
  if (out['status'] === 'draft') {
    out['isActive'] = false;
    delete out['status'];
  } else if (out['status'] === 'published') {
    out['isActive'] = true;
    delete out['status'];
  }
  // Auto-generate slug if absent
  if (!out['slug'] && typeof out['title'] === 'string') {
    out['slug'] =
      (out['title'] as string)
        .toLowerCase()
        .trim()
        .replace(/[^a-z0-9]+/g, '-')
        .replace(/^-|-$/g, '')
        .slice(0, 120) || 'untitled';
  }
  return out;
}, _adminKbCreateSchemaInner);
export type AdminKbCreate = z.infer<typeof adminKbCreateSchema>;

// PATCH: update parent fields and/or upsert a translation row.
// locale is required when sending translation fields (slug/title/bodyMd).
export const adminKbUpdateSchema = z.object({
  locale: z.enum(['he', 'en']).optional(),
  slug: z
    .string()
    .trim()
    .regex(/^[a-z0-9][a-z0-9-]*$/)
    .min(2)
    .max(120)
    .optional(),
  title: z.string().trim().min(1).max(200).optional(),
  bodyMd: z.string().trim().min(1).max(20_000).optional(),
  category: z.enum(['faq', 'policy', 'refund_rules', 'redemption_rules', 'internal']).optional(),
  tags: z.array(z.string().trim().min(1).max(40)).max(20).optional(),
  visibility: z.enum(['public', 'internal']).optional(),
  isActive: z.boolean().optional(),
});
export type AdminKbUpdate = z.infer<typeof adminKbUpdateSchema>;

// ─── PATCH /api/admin/moderation/support-settings ────────────────────────────

const emailArray = z.email().array();

export const supportSettingsPatchSchema = z.object({
  support_vendor_window_hours: z.coerce.number().int().min(1).max(720).optional(),
  support_autoclose_days: z.coerce.number().int().min(1).max(90).optional(),
  support_notification_emails: emailArray.optional(), // stored as JSON string
  support_media_max_images: z.coerce.number().int().min(1).max(50).optional(),
  support_media_max_mb: z.coerce.number().int().min(1).max(50).optional(),
  support_return_window_days: z.coerce.number().int().min(1).max(365).optional(),
  support_reopen_limit: z.coerce.number().int().min(0).max(10).optional(),
}); // Empty body is a valid no-op PATCH — caller treats it as 200 no-op

// ─── GET /api/admin/support/metrics ──────────────────────────────────────────

const _coerceOptionalDate = (defaultFn: () => Date) =>
  z.preprocess((v) => {
    if (v === undefined || v === null || v === '') return defaultFn();
    return v;
  }, z.coerce.date());

export const metricsRangeSchema = z
  .object({
    from: _coerceOptionalDate(() => new Date(Date.now() - 30 * 864e5)),
    to: _coerceOptionalDate(() => new Date()),
  })
  .refine((d) => d.from <= d.to, { path: ['from'], message: 'from must be ≤ to' });
