import type {
  AlertRuleRequest,
  AlertRuleResponse,
  AlertCondition,
} from '../../../api/queries/alertRules';
import type { ConditionKind, ExchangeFireMode, Severity, TargetKind } from '../enums';

export type WizardStep = 'scope' | 'condition' | 'trigger' | 'notify' | 'review';
export const WIZARD_STEPS: WizardStep[] = ['scope', 'condition', 'trigger', 'notify', 'review'];

export interface FormState {
  name: string;
  description: string;
  severity: Severity;
  enabled: boolean;

  // Scope (radio: env-wide | app | route | agent)
  scopeKind: 'env' | 'app' | 'route' | 'agent';
  appSlug: string;
  routeId: string;
  agentId: string;

  conditionKind: ConditionKind;
  condition: Partial<AlertCondition>;

  evaluationIntervalSeconds: number;
  forDurationSeconds: number;
  reNotifyMinutes: number;

  notificationTitleTmpl: string;
  notificationMessageTmpl: string;

  webhooks: Array<{
    outboundConnectionId: string;
    bodyOverride: string;
    headerOverrides: Array<{ key: string; value: string }>;
  }>;

  targets: Array<{ kind: TargetKind; targetId: string }>;
}

export function initialForm(existing?: AlertRuleResponse): FormState {
  if (!existing) {
    return {
      name: '',
      description: '',
      severity: 'WARNING',
      enabled: true,
      scopeKind: 'env',
      appSlug: '',
      routeId: '',
      agentId: '',
      conditionKind: 'ROUTE_METRIC',
      // Pre-populate a valid ROUTE_METRIC default so a rule can be saved without
      // the user needing to fill in every condition field. Values chosen to be
      // sane for "error rate" alerts on almost any route.
      condition: {
        kind: 'ROUTE_METRIC',
        scope: {},
        metric: 'ERROR_RATE',
        comparator: 'GT',
        threshold: 0.05,
        windowSeconds: 300,
      } as unknown as Partial<AlertCondition>,
      evaluationIntervalSeconds: 60,
      forDurationSeconds: 0,
      reNotifyMinutes: 60,
      notificationTitleTmpl: '{{rule.name}} is firing',
      notificationMessageTmpl: 'Alert {{alert.id}} fired at {{alert.firedAt}}',
      webhooks: [],
      targets: [],
    };
  }
  const scope = ((existing.condition as { scope?: { appSlug?: string; routeId?: string; agentId?: string } } | undefined)?.scope) ?? {};
  const scopeKind: FormState['scopeKind'] = scope.agentId
    ? 'agent'
    : scope.routeId
      ? 'route'
      : scope.appSlug
        ? 'app'
        : 'env';
  return {
    name: existing.name ?? '',
    description: existing.description ?? '',
    severity: (existing.severity ?? 'WARNING') as FormState['severity'],
    enabled: existing.enabled ?? true,
    scopeKind,
    appSlug: scope.appSlug ?? '',
    routeId: scope.routeId ?? '',
    agentId: scope.agentId ?? '',
    conditionKind: (existing.conditionKind ?? 'ROUTE_METRIC') as ConditionKind,
    condition: (existing.condition ?? { kind: existing.conditionKind }) as Partial<AlertCondition>,
    evaluationIntervalSeconds: existing.evaluationIntervalSeconds ?? 60,
    forDurationSeconds: existing.forDurationSeconds ?? 0,
    reNotifyMinutes: existing.reNotifyMinutes ?? 60,
    notificationTitleTmpl: existing.notificationTitleTmpl ?? '{{rule.name}} is firing',
    notificationMessageTmpl: existing.notificationMessageTmpl ?? 'Alert {{alert.id}} fired at {{alert.firedAt}}',
    webhooks: (existing.webhooks ?? []).map((w) => ({
      outboundConnectionId: (w.outboundConnectionId ?? '') as string,
      bodyOverride: w.bodyOverride ?? '',
      headerOverrides: Object.entries((w.headerOverrides ?? {}) as Record<string, string>)
        .map(([key, value]) => ({ key, value })),
    })),
    targets: (existing.targets ?? []).map((t) => ({
      kind: (t.kind ?? 'USER') as TargetKind,
      targetId: t.targetId ?? '',
    })),
  };
}

export function toRequest(f: FormState): AlertRuleRequest {
  const scope: Record<string, string | undefined> = {};
  if (f.scopeKind === 'app' || f.scopeKind === 'route' || f.scopeKind === 'agent') scope.appSlug = f.appSlug || undefined;
  if (f.scopeKind === 'route') scope.routeId = f.routeId || undefined;
  if (f.scopeKind === 'agent') scope.agentId = f.agentId || undefined;

  const condition = { ...(f.condition as Record<string, unknown>), kind: f.conditionKind, scope } as unknown as AlertCondition;

  return {
    name: f.name,
    description: f.description || undefined,
    severity: f.severity,
    enabled: f.enabled,
    conditionKind: f.conditionKind,
    condition,
    evaluationIntervalSeconds: f.evaluationIntervalSeconds,
    forDurationSeconds: f.forDurationSeconds,
    reNotifyMinutes: f.reNotifyMinutes,
    notificationTitleTmpl: f.notificationTitleTmpl,
    notificationMessageTmpl: f.notificationMessageTmpl,
    webhooks: f.webhooks.map((w) => ({
      outboundConnectionId: w.outboundConnectionId,
      bodyOverride: w.bodyOverride || undefined,
      headerOverrides: Object.fromEntries(w.headerOverrides.filter((h) => h.key.trim()).map((h) => [h.key.trim(), h.value])),
    })),
    targets: f.targets.map((t) => ({ kind: t.kind, targetId: t.targetId })),
  } as AlertRuleRequest;
}

/**
 * Pure helper for the ExchangeMatchForm's Fire-mode <Select>. Guarantees state
 * hygiene across toggles:
 *
 *   - Switching to PER_EXCHANGE clears COUNT_IN_WINDOW-only condition fields
 *     (threshold, windowSeconds) AND forces top-level reNotifyMinutes = 0
 *     and forDurationSeconds = 0 — PER_EXCHANGE is exactly-once-per-exchange,
 *     so re-notify cadence and hold-duration are meaningless and must not leak
 *     into toRequest().
 *   - Switching back to COUNT_IN_WINDOW resets threshold/windowSeconds to 0
 *     (never restoring stale values from the previous COUNT_IN_WINDOW session).
 *
 * No-op for non-EXCHANGE_MATCH conditions. Returns a new form object.
 */
export function applyFireModeChange(form: FormState, newMode: ExchangeFireMode): FormState {
  const c = form.condition as Record<string, unknown>;
  if (c.kind !== 'EXCHANGE_MATCH') return form;
  const base: FormState = {
    ...form,
    condition: {
      ...c,
      fireMode: newMode,
      threshold: 0,
      windowSeconds: 0,
    } as FormState['condition'],
  };
  if (newMode === 'PER_EXCHANGE') {
    return { ...base, reNotifyMinutes: 0, forDurationSeconds: 0 };
  }
  return base;
}

export function validateStep(step: WizardStep, f: FormState): string[] {
  const errs: string[] = [];
  if (step === 'scope') {
    if (!f.name.trim()) errs.push('Name is required.');
    if (f.scopeKind !== 'env' && !f.appSlug.trim()) errs.push('App is required for app/route/agent scope.');
    if (f.scopeKind === 'route' && !f.routeId.trim()) errs.push('Route id is required for route scope.');
    if (f.scopeKind === 'agent' && !f.agentId.trim()) errs.push('Agent id is required for agent scope.');
  }
  if (step === 'condition') {
    if (!f.conditionKind) errs.push('Condition kind is required.');
    if (f.conditionKind === 'EXCHANGE_MATCH') {
      const c = f.condition as Record<string, unknown>;
      if (!c.fireMode) {
        errs.push('Fire mode is required.');
      } else if (c.fireMode === 'COUNT_IN_WINDOW') {
        if (c.threshold == null) errs.push('Threshold is required for COUNT_IN_WINDOW.');
        if (c.windowSeconds == null) errs.push('Window (seconds) is required for COUNT_IN_WINDOW.');
      }
    }
    if (f.conditionKind === 'AGENT_LIFECYCLE') {
      const c = f.condition as Record<string, unknown>;
      const types = Array.isArray(c.eventTypes) ? (c.eventTypes as string[]) : [];
      if (types.length === 0) errs.push('Pick at least one event type.');
      const within = c.withinSeconds as number | undefined;
      if (within == null || within < 1) errs.push('Lookback window must be \u2265 1 second.');
    }
  }
  if (step === 'trigger') {
    if (f.evaluationIntervalSeconds < 5) errs.push('Evaluation interval must be \u2265 5 s.');
    if (f.forDurationSeconds < 0) errs.push('For-duration must be \u2265 0.');
    if (f.reNotifyMinutes < 0) errs.push('Re-notify cadence must be \u2265 0.');
  }
  if (step === 'notify') {
    if (!f.notificationTitleTmpl.trim()) errs.push('Notification title template is required.');
    if (!f.notificationMessageTmpl.trim()) errs.push('Notification message template is required.');
  }
  return errs;
}
