"use client";

import { useEffect, useId, useState, type ReactNode } from "react";
import { Button } from "@/components/Button";
import { CampaignFieldLabel } from "@/components/dashboard/CampaignFieldLabel";
import { CampaignGenderPicker } from "@/components/dashboard/CampaignGenderPicker";
import { CampaignLocationPicker } from "@/components/dashboard/CampaignLocationPicker";
import { SocialProviderIcon } from "@/components/dashboard/SocialProviderIcon";
import { Card } from "@/components/ui/Card";
import { fieldClassName, fieldInvalidClassName, textareaClassName } from "@/components/ui/field-styles";
import { cn } from "@/lib/cn";
import {
  addOrIncrementDeliverable,
  buildWizardPayload,
  clampQuantity,
  defaultCampaignWizardValues,
  deliverablesForPlatform,
  firstFieldError,
  platformHasConfiguredDeliverables,
  removePlatformDeliverables,
  stepContainingFirstError,
  validateWizardStep,
  WIZARD_STEPS,
  type CampaignDeliverableFormItem,
  type CampaignWizardValues,
  type WizardStepId,
} from "@/lib/campaign-wizard";
import { CAMPAIGN_FIELD_REQUIREMENTS } from "@/lib/campaign-field-labels";
import {
  CAMPAIGN_AUDIENCE_AGE_RANGES,
  CAMPAIGN_PLATFORMS,
  campaignDeliverableLabel,
  deliverableHasExtraDetails,
  deliverableTypesForPlatform,
} from "@/lib/campaigns";
import { CREATOR_NICHE_OPTIONS } from "@/lib/creator-personal-info";
import { socialProviderLabel } from "@/lib/social-providers";
import type { ValidationErrors } from "@/lib/api";
import type {
  CampaignAudienceAgeRange,
  CampaignDeliverableType,
  CampaignStatus,
} from "@/types/campaign";
import type { SocialProvider } from "@/types/social-account";

function FieldError({ id, message }: { id: string; message?: string }) {
  if (!message) return null;
  return (
    <p id={id} className="mt-1 text-[0.75rem] text-accent" role="alert">
      {message}
    </p>
  );
}

function TextField({
  id,
  label,
  required = false,
  value,
  onChange,
  error,
  type = "text",
  disabled,
  hint,
  inputMode,
  min,
  max,
}: {
  id: string;
  label: string;
  required?: boolean;
  value: string;
  onChange: (value: string) => void;
  error?: string;
  type?: "text" | "date" | "number";
  disabled?: boolean;
  hint?: string;
  inputMode?: "decimal" | "numeric";
  min?: number | string;
  max?: number | string;
}) {
  const errorId = `${id}-error`;
  return (
    <div>
      <CampaignFieldLabel htmlFor={id} label={label} required={required} />
      <input
        id={id}
        type={type}
        value={value}
        disabled={disabled}
        inputMode={inputMode}
        min={min}
        max={max}
        required={required}
        aria-required={required || undefined}
        aria-invalid={error ? true : undefined}
        aria-describedby={error ? errorId : hint ? `${id}-hint` : undefined}
        className={cn(fieldClassName, error && fieldInvalidClassName)}
        onChange={(event) => onChange(event.target.value)}
      />
      {hint ? (
        <p id={`${id}-hint`} className="mt-1 text-[0.75rem] text-ink-40">
          {hint}
        </p>
      ) : null}
      <FieldError id={errorId} message={error} />
    </div>
  );
}

function TextAreaField({
  id,
  label,
  required = false,
  value,
  onChange,
  error,
  disabled,
  rows = 4,
  hint,
}: {
  id: string;
  label: string;
  required?: boolean;
  value: string;
  onChange: (value: string) => void;
  error?: string;
  disabled?: boolean;
  rows?: number;
  hint?: string;
}) {
  const errorId = `${id}-error`;
  return (
    <div>
      <CampaignFieldLabel htmlFor={id} label={label} required={required} />
      <textarea
        id={id}
        value={value}
        disabled={disabled}
        rows={rows}
        required={required}
        aria-required={required || undefined}
        aria-invalid={error ? true : undefined}
        aria-describedby={error ? errorId : hint ? `${id}-hint` : undefined}
        className={cn(textareaClassName, error && fieldInvalidClassName)}
        onChange={(event) => onChange(event.target.value)}
      />
      {hint ? (
        <p id={`${id}-hint`} className="mt-1 text-[0.75rem] text-ink-40">
          {hint}
        </p>
      ) : null}
      <FieldError id={errorId} message={error} />
    </div>
  );
}

function WizardStepper({
  step,
  highestReached,
  onGoTo,
  disabled,
}: {
  step: WizardStepId;
  highestReached: WizardStepId;
  onGoTo: (next: WizardStepId) => void;
  disabled: boolean;
}) {
  const currentMeta = WIZARD_STEPS.find((item) => item.id === step) ?? WIZARD_STEPS[0];

  return (
    <nav aria-label="Campaign creation steps">
      <div className="sm:hidden">
        <p className="text-[0.75rem] font-medium uppercase tracking-[0.06em] text-ink-40">
          Step {step} of 3
        </p>
        <p className="mt-1 text-[1rem] font-semibold text-primary">{currentMeta.label}</p>
      </div>

      <ol className="hidden items-center gap-2 sm:flex">
        {WIZARD_STEPS.map((item, index) => {
          const completed = item.id < step;
          const current = item.id === step;
          const reachable = item.id <= highestReached;
          const content = (
            <>
              <span
                className={cn(
                  "inline-flex size-6 items-center justify-center rounded-full text-[0.75rem] font-semibold",
                  current && "bg-primary text-white",
                  completed && "bg-primary text-white",
                  !current && !completed && "bg-bg text-ink-40",
                )}
                aria-hidden
              >
                {completed ? (
                  <svg viewBox="0 0 16 16" className="size-3.5" fill="none" aria-hidden>
                    <path
                      d="M3.5 8.5 6.5 11.5 12.5 4.5"
                      stroke="currentColor"
                      strokeWidth="1.8"
                      strokeLinecap="round"
                      strokeLinejoin="round"
                    />
                  </svg>
                ) : (
                  item.id
                )}
              </span>
              <span
                className={cn(
                  "text-[0.875rem]",
                  current ? "font-semibold text-primary" : completed ? "font-medium text-primary" : "text-ink-40",
                )}
              >
                {item.label}
              </span>
            </>
          );

          return (
            <li key={item.id} className="flex items-center gap-2">
              {index > 0 ? (
                <span className="mx-1 text-ink-40" aria-hidden>
                  →
                </span>
              ) : null}
              {completed && reachable ? (
                <button
                  type="button"
                  disabled={disabled}
                  className="inline-flex items-center gap-2 rounded-pv focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
                  onClick={() => onGoTo(item.id)}
                >
                  {content}
                </button>
              ) : (
                <span
                  className="inline-flex items-center gap-2"
                  aria-current={current ? "step" : undefined}
                >
                  {content}
                </span>
              )}
            </li>
          );
        })}
      </ol>
    </nav>
  );
}

function DeliverableCard({
  item,
  index,
  disabled,
  fieldErrors,
  instructionsOpen,
  onToggleInstructions,
  onChange,
  onRemove,
}: {
  item: CampaignDeliverableFormItem;
  index: number;
  disabled: boolean;
  fieldErrors: ValidationErrors;
  instructionsOpen: boolean;
  onToggleInstructions: () => void;
  onChange: (patch: Partial<CampaignDeliverableFormItem>) => void;
  onRemove: () => void;
}) {
  const baseId = `deliverable-${item.id}`;
  const hasInstructions = deliverableHasExtraDetails(item);
  const typeField = CAMPAIGN_FIELD_REQUIREMENTS.deliverableType;
  const quantityField = CAMPAIGN_FIELD_REQUIREMENTS.quantity;
  const descriptionField = CAMPAIGN_FIELD_REQUIREMENTS.deliverableDescription;
  const instructionsField = CAMPAIGN_FIELD_REQUIREMENTS.creatorInstructions;
  const referenceField = CAMPAIGN_FIELD_REQUIREMENTS.referenceUrl;
  const quantityError = firstFieldError(fieldErrors, `deliverables.${index}.quantity`);
  const typeError = firstFieldError(fieldErrors, `deliverables.${index}.type`);

  return (
    <div className="rounded-pv border border-line bg-surface p-3 sm:p-4">
      <div className="flex items-start justify-between gap-3">
        <div>
          <CampaignFieldLabel
            as="p"
            label={typeField.label}
            required={typeField.required}
            className="mb-1"
          />
          <p
            id={`${baseId}-type`}
            className="text-[0.9375rem] font-semibold text-primary"
            aria-required={typeField.required || undefined}
          >
            {campaignDeliverableLabel(item.type)}
          </p>
          <FieldError id={`${baseId}-type-error`} message={typeError} />
        </div>
        <button
          type="button"
          disabled={disabled}
          aria-label={`Remove ${campaignDeliverableLabel(item.type)}`}
          className="rounded-pv px-2 py-1 text-[0.8125rem] text-ink-40 transition hover:bg-bg hover:text-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
          onClick={onRemove}
        >
          ×
        </button>
      </div>

      <div className="mt-3 flex items-center justify-between gap-3">
        <CampaignFieldLabel
          htmlFor={`${baseId}-qty`}
          label={quantityField.label}
          required={quantityField.required}
          className="mb-0"
        />
        <div className="inline-flex items-center gap-1">
          <button
            type="button"
            disabled={disabled}
            aria-label="Decrease quantity"
            className="inline-flex size-8 items-center justify-center rounded-pv border border-line text-primary transition hover:border-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent disabled:opacity-70"
            onClick={() => onChange({ quantity: clampQuantity(item.quantity, -1) })}
          >
            −
          </button>
          <input
            id={`${baseId}-qty`}
            type="number"
            min={1}
            max={100}
            value={item.quantity}
            disabled={disabled}
            required={quantityField.required}
            aria-required={quantityField.required || undefined}
            aria-invalid={quantityError ? true : undefined}
            aria-describedby={quantityError ? `${baseId}-qty-error` : undefined}
            className={cn(
              "h-8 w-14 rounded-pv border border-line bg-bg text-center text-sm",
              quantityError && fieldInvalidClassName,
            )}
            onChange={(event) => onChange({ quantity: event.target.value })}
          />
          <button
            type="button"
            disabled={disabled}
            aria-label="Increase quantity"
            className="inline-flex size-8 items-center justify-center rounded-pv border border-line text-primary transition hover:border-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent disabled:opacity-70"
            onClick={() => onChange({ quantity: clampQuantity(item.quantity, 1) })}
          >
            +
          </button>
        </div>
      </div>
      <FieldError id={`${baseId}-qty-error`} message={quantityError} />

      <div className="mt-3">
        <TextAreaField
          id={`${baseId}-description`}
          label={descriptionField.label}
          required={descriptionField.required}
          value={item.description}
          disabled={disabled}
          rows={2}
          error={firstFieldError(fieldErrors, `deliverables.${index}.description`)}
          onChange={(value) => onChange({ description: value })}
        />
      </div>

      {!instructionsOpen ? (
        <button
          type="button"
          disabled={disabled}
          className="mt-3 text-[0.8125rem] font-medium text-primary underline-offset-2 hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
          onClick={onToggleInstructions}
        >
          {hasInstructions ? "Edit instructions" : "+ Add instructions"}
        </button>
      ) : (
        <div className="mt-4 space-y-3 border-t border-line pt-4">
          <TextAreaField
            id={`${baseId}-instructions`}
            label={instructionsField.label}
            required={instructionsField.required}
            value={item.creator_instructions}
            disabled={disabled}
            rows={3}
            error={firstFieldError(fieldErrors, `deliverables.${index}.creator_instructions`)}
            onChange={(value) => onChange({ creator_instructions: value })}
          />
          <TextField
            id={`${baseId}-reference`}
            label={referenceField.label}
            required={referenceField.required}
            value={item.reference_url}
            disabled={disabled}
            error={firstFieldError(fieldErrors, `deliverables.${index}.reference_url`)}
            onChange={(value) => onChange({ reference_url: value })}
          />
          <button
            type="button"
            disabled={disabled}
            className="text-[0.8125rem] font-medium text-ink-60 hover:text-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
            onClick={onToggleInstructions}
          >
            Hide instructions
          </button>
        </div>
      )}
    </div>
  );
}

function NetworkSection({
  platform,
  values,
  disabled,
  fieldErrors,
  instructionsOpenIds,
  onToggleInstructions,
  onUpdateDeliverable,
  onRemoveDeliverable,
  onAddType,
  typePickerOpen,
  onToggleTypePicker,
}: {
  platform: SocialProvider;
  values: CampaignWizardValues;
  disabled: boolean;
  fieldErrors: ValidationErrors;
  instructionsOpenIds: Set<string>;
  onToggleInstructions: (id: string) => void;
  onUpdateDeliverable: (id: string, patch: Partial<CampaignDeliverableFormItem>) => void;
  onRemoveDeliverable: (id: string) => void;
  onAddType: (type: CampaignDeliverableType) => void;
  typePickerOpen: boolean;
  onToggleTypePicker: () => void;
}) {
  const items = deliverablesForPlatform(values, platform);
  const types = deliverableTypesForPlatform(platform);
  const label = socialProviderLabel(platform);

  return (
    <section className="space-y-3">
      <div className="border-b border-line pb-2">
        <h3 className="text-[0.9375rem] font-semibold text-primary">{label}</h3>
      </div>

      {items.length === 0 ? (
        <p className="text-[0.8125rem] text-ink-40">Add your first {label} deliverable</p>
      ) : (
        <div className="space-y-3">
          {items.map((item) => {
            const index = values.deliverables.findIndex((entry) => entry.id === item.id);
            return (
              <DeliverableCard
                key={item.id}
                item={item}
                index={index}
                disabled={disabled}
                fieldErrors={fieldErrors}
                instructionsOpen={instructionsOpenIds.has(item.id)}
                onToggleInstructions={() => onToggleInstructions(item.id)}
                onChange={(patch) => onUpdateDeliverable(item.id, patch)}
                onRemove={() => onRemoveDeliverable(item.id)}
              />
            );
          })}
        </div>
      )}

      <div>
        <Button
          type="button"
          variant="secondary"
          size="sm"
          disabled={disabled || values.deliverables.length >= 20}
          onClick={onToggleTypePicker}
        >
          + Add {label} deliverable
        </Button>
        {typePickerOpen ? (
          <div
            className="mt-2 rounded-pv border border-line bg-bg p-2"
            role="listbox"
            aria-label={`${label} deliverable types`}
          >
            {types.map((type) => (
              <button
                key={type}
                type="button"
                role="option"
                disabled={disabled}
                className="flex w-full rounded-pv px-2.5 py-2 text-left text-[0.8125rem] text-primary transition hover:bg-surface focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
                onClick={() => onAddType(type)}
              >
                {campaignDeliverableLabel(type)}
              </button>
            ))}
          </div>
        ) : null}
      </div>
    </section>
  );
}

export function BrandCampaignCreateWizard({
  fieldErrors,
  busyAction,
  onSubmit,
  onCancel,
}: {
  fieldErrors: ValidationErrors;
  busyAction: "draft" | "active" | null;
  onSubmit: (values: CampaignWizardValues, status: CampaignStatus) => void;
  onCancel: () => void;
}) {
  const formId = useId();
  const [values, setValues] = useState<CampaignWizardValues>(defaultCampaignWizardValues);
  const [step, setStep] = useState<WizardStepId>(1);
  const [highestReached, setHighestReached] = useState<WizardStepId>(1);
  const [localErrors, setLocalErrors] = useState<ValidationErrors>({});
  const [instructionsOpenIds, setInstructionsOpenIds] = useState<Set<string>>(new Set());
  const [typePickerPlatform, setTypePickerPlatform] = useState<SocialProvider | null>(null);
  const [pendingRemovePlatform, setPendingRemovePlatform] = useState<SocialProvider | null>(null);
  const disabled = busyAction !== null;

  const errors = { ...localErrors, ...fieldErrors };
  const stepMeta = WIZARD_STEPS.find((item) => item.id === step) ?? WIZARD_STEPS[0];

  useEffect(() => {
    if (Object.keys(fieldErrors).length === 0) return;
    const target = stepContainingFirstError(fieldErrors);
    setStep(target);
    setHighestReached((current) => (target > current ? target : current));
  }, [fieldErrors]);

  function update<K extends keyof CampaignWizardValues>(key: K, value: CampaignWizardValues[K]) {
    setValues((current) => ({ ...current, [key]: value }));
  }

  function toggleCategory(value: string) {
    setValues((current) => {
      const exists = current.categories.includes(value);
      return {
        ...current,
        categories: exists
          ? current.categories.filter((item) => item !== value)
          : [...current.categories, value],
      };
    });
  }

  function toggleAgeRange(value: CampaignAudienceAgeRange) {
    setValues((current) => {
      const exists = current.ageRanges.includes(value);
      return {
        ...current,
        ageRanges: exists
          ? current.ageRanges.filter((item) => item !== value)
          : [...current.ageRanges, value],
      };
    });
  }

  function requestTogglePlatform(platform: SocialProvider) {
    const exists = values.platforms.includes(platform);
    if (!exists) {
      setValues((current) => ({
        ...current,
        platforms: [...current.platforms, platform],
      }));
      return;
    }

    if (platformHasConfiguredDeliverables(values, platform)) {
      setPendingRemovePlatform(platform);
      return;
    }

    setValues((current) => ({
      ...current,
      platforms: current.platforms.filter((item) => item !== platform),
    }));
  }

  function confirmRemovePlatform() {
    if (!pendingRemovePlatform) return;
    setValues((current) => removePlatformDeliverables(current, pendingRemovePlatform));
    setPendingRemovePlatform(null);
    setTypePickerPlatform(null);
  }

  function goNext() {
    const stepErrors = validateWizardStep(step, values);
    if (Object.keys(stepErrors).length > 0) {
      setLocalErrors(stepErrors);
      return;
    }
    setLocalErrors({});
    if (step < 3) {
      const next = (step + 1) as WizardStepId;
      setStep(next);
      setHighestReached((current) => (next > current ? next : current));
    }
  }

  function goBack() {
    setLocalErrors({});
    if (step > 1) {
      setStep((current) => (current - 1) as WizardStepId);
    } else {
      onCancel();
    }
  }

  function handleSaveDraft() {
    const built = buildWizardPayload(values, "draft");
    if ("errors" in built) {
      setLocalErrors(built.errors);
      setStep(stepContainingFirstError(built.errors));
      return;
    }
    setLocalErrors({});
    onSubmit(values, "draft");
  }

  function handleCreate() {
    const stepErrors = validateWizardStep(3, values);
    if (Object.keys(stepErrors).length > 0) {
      setLocalErrors(stepErrors);
      return;
    }
    const built = buildWizardPayload(values, "active");
    if ("errors" in built) {
      setLocalErrors(built.errors);
      setStep(stepContainingFirstError(built.errors));
      return;
    }
    setLocalErrors({});
    onSubmit(values, "active");
  }

  let stepContent: ReactNode = null;

  if (step === 1) {
    stepContent = (
      <div className="space-y-4">
        <TextField
          id={`${formId}-name`}
          label={CAMPAIGN_FIELD_REQUIREMENTS.name.label}
          required={CAMPAIGN_FIELD_REQUIREMENTS.name.required}
          value={values.name}
          disabled={disabled}
          error={firstFieldError(errors, "name")}
          onChange={(value) => update("name", value)}
        />
        <TextAreaField
          id={`${formId}-description`}
          label={CAMPAIGN_FIELD_REQUIREMENTS.descriptionWizard.label}
          required={CAMPAIGN_FIELD_REQUIREMENTS.descriptionWizard.required}
          value={values.description}
          disabled={disabled}
          hint="What should creators achieve with this campaign?"
          error={firstFieldError(errors, "description")}
          onChange={(value) => update("description", value)}
        />
        <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
          <TextField
            id={`${formId}-start`}
            label={CAMPAIGN_FIELD_REQUIREMENTS.startDate.label}
            required={CAMPAIGN_FIELD_REQUIREMENTS.startDate.required}
            type="date"
            value={values.startDate}
            disabled={disabled}
            error={firstFieldError(errors, "start_date")}
            onChange={(value) => update("startDate", value)}
          />
          <TextField
            id={`${formId}-end`}
            label={CAMPAIGN_FIELD_REQUIREMENTS.endDate.label}
            required={CAMPAIGN_FIELD_REQUIREMENTS.endDate.required}
            type="date"
            value={values.endDate}
            disabled={disabled}
            error={firstFieldError(errors, "end_date")}
            onChange={(value) => update("endDate", value)}
          />
        </div>
        <TextField
          id={`${formId}-budget`}
          label={CAMPAIGN_FIELD_REQUIREMENTS.budget.label}
          required={CAMPAIGN_FIELD_REQUIREMENTS.budget.required}
          value={values.budgetMajor}
          disabled={disabled}
          inputMode="decimal"
          hint="USD. Enter dollars. Stored as cents (e.g. 5000 = $5,000.00)."
          error={firstFieldError(errors, "budget_amount")}
          onChange={(value) => update("budgetMajor", value)}
        />
      </div>
    );
  }

  if (step === 2) {
    const networksLabelId = `${formId}-networks-label`;
    const categoryLabelId = `${formId}-category-label`;
    const ageLabelId = `${formId}-age-label`;
    const ageHintId = `${formId}-age-hint`;
    const ageErrorId = `${formId}-age-error`;
    const ageError = firstFieldError(errors, "target_audience.age_ranges");
    stepContent = (
      <div className="space-y-6">
        <div
          role="group"
          aria-labelledby={networksLabelId}
          aria-required={CAMPAIGN_FIELD_REQUIREMENTS.networks.required || undefined}
        >
          <CampaignFieldLabel
            as="p"
            id={networksLabelId}
            label={CAMPAIGN_FIELD_REQUIREMENTS.networks.label}
            required={CAMPAIGN_FIELD_REQUIREMENTS.networks.required}
            className="mb-0 text-[0.875rem] font-semibold text-primary"
          />
          <p className="mt-1 text-[0.8125rem] text-ink-40">
            Select where this campaign will run. Deliverables in the next step are limited to these
            networks.
          </p>
          <div className="mt-3 grid grid-cols-2 gap-2 sm:grid-cols-3 md:grid-cols-5">
            {CAMPAIGN_PLATFORMS.map((platform) => {
              const selected = values.platforms.includes(platform);
              return (
                <button
                  key={platform}
                  type="button"
                  disabled={disabled}
                  aria-pressed={selected}
                  className={cn(
                    "inline-flex items-center gap-2 rounded-pv border px-2.5 py-2 text-left text-[0.8125rem] font-medium transition focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
                    selected
                      ? "border-primary bg-bg text-primary"
                      : "border-line bg-surface text-ink-60 hover:border-primary/40",
                    disabled && "cursor-not-allowed opacity-70",
                  )}
                  onClick={() => requestTogglePlatform(platform)}
                >
                  <SocialProviderIcon provider={platform} className="size-4" />
                  <span>{socialProviderLabel(platform)}</span>
                </button>
              );
            })}
          </div>
          <FieldError id={`${formId}-platforms-error`} message={firstFieldError(errors, "platforms")} />
        </div>

        <div>
          <h3 className="text-[0.875rem] font-semibold text-primary">Target audience</h3>
          <p className="mt-1 text-[0.8125rem] text-ink-40">Optional targeting details for creators.</p>
          <div className="mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2">
            <CampaignLocationPicker
              selected={values.locations}
              disabled={disabled}
              error={
                firstFieldError(errors, "target_audience.locations") ||
                firstFieldError(errors, "target_audience.location")
              }
              onChange={(locations) => update("locations", locations)}
            />
            <CampaignGenderPicker
              selected={values.genders}
              disabled={disabled}
              error={firstFieldError(errors, "target_audience.genders")}
              onChange={(genders) => update("genders", genders)}
            />
            <div
              className="sm:col-span-2"
              role="group"
              aria-labelledby={ageLabelId}
              aria-describedby={ageError ? `${ageHintId} ${ageErrorId}` : ageHintId}
            >
              <CampaignFieldLabel
                as="p"
                id={ageLabelId}
                label={CAMPAIGN_FIELD_REQUIREMENTS.audienceAge.label}
                required={CAMPAIGN_FIELD_REQUIREMENTS.audienceAge.required}
                className="mb-1.5"
              />
              <p id={ageHintId} className="mb-2 text-[0.75rem] text-ink-40">
                Select the age groups you want to reach.
              </p>
              <div className="flex flex-wrap gap-1.5">
                {CAMPAIGN_AUDIENCE_AGE_RANGES.map((option) => {
                  const selected = values.ageRanges.includes(option.value);
                  const checkboxId = `${formId}-age-${option.value}`;
                  return (
                    <label
                      key={option.value}
                      htmlFor={checkboxId}
                      className={cn(
                        "inline-flex cursor-pointer items-center gap-2 rounded-pv border px-2.5 py-1.5 text-[0.8125rem] font-medium transition focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-accent",
                        selected
                          ? "border-primary bg-bg text-primary"
                          : "border-line bg-surface text-ink-60 hover:border-primary/40",
                        disabled && "cursor-not-allowed opacity-70",
                      )}
                    >
                      <input
                        id={checkboxId}
                        type="checkbox"
                        className="size-3.5 accent-primary"
                        checked={selected}
                        disabled={disabled}
                        onChange={() => toggleAgeRange(option.value)}
                      />
                      <span>{option.label}</span>
                    </label>
                  );
                })}
              </div>
              <FieldError id={ageErrorId} message={ageError} />
            </div>
            <div
              className="sm:col-span-2"
              role="group"
              aria-labelledby={categoryLabelId}
            >
              <CampaignFieldLabel
                as="p"
                id={categoryLabelId}
                label={CAMPAIGN_FIELD_REQUIREMENTS.category.label}
                required={CAMPAIGN_FIELD_REQUIREMENTS.category.required}
                className="mb-1.5"
              />
              <p className="mb-2 text-[0.75rem] text-ink-40">
                Same categories creators use on their profiles.
              </p>
              <div className="flex flex-wrap gap-1.5">
                {CREATOR_NICHE_OPTIONS.map((option) => {
                  const selected = values.categories.includes(option.value);
                  return (
                    <button
                      key={option.value}
                      type="button"
                      disabled={disabled}
                      aria-pressed={selected}
                      className={cn(
                        "rounded-pv border px-2.5 py-1.5 text-[0.8125rem] font-medium transition focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
                        selected
                          ? "border-primary bg-bg text-primary"
                          : "border-line bg-surface text-ink-60 hover:border-primary/40",
                        disabled && "cursor-not-allowed opacity-70",
                      )}
                      onClick={() => toggleCategory(option.value)}
                    >
                      {option.label}
                    </button>
                  );
                })}
              </div>
              <FieldError
                id={`${formId}-categories-error`}
                message={firstFieldError(errors, "target_audience.interests")}
              />
            </div>
          </div>
        </div>
      </div>
    );
  }

  if (step === 3) {
    stepContent = (
      <div className="space-y-6">
        <FieldError id={`${formId}-deliverables-error`} message={firstFieldError(errors, "deliverables")} />
        {values.platforms.length === 0 ? (
          <p className="text-[0.8125rem] text-ink-40">
            Select at least one network in Audience before adding deliverables.
          </p>
        ) : (
          values.platforms.map((platform) => (
            <NetworkSection
              key={platform}
              platform={platform}
              values={values}
              disabled={disabled}
              fieldErrors={errors}
              instructionsOpenIds={instructionsOpenIds}
              typePickerOpen={typePickerPlatform === platform}
              onToggleTypePicker={() =>
                setTypePickerPlatform((current) => (current === platform ? null : platform))
              }
              onToggleInstructions={(id) =>
                setInstructionsOpenIds((current) => {
                  const next = new Set(current);
                  if (next.has(id)) next.delete(id);
                  else next.add(id);
                  return next;
                })
              }
              onUpdateDeliverable={(id, patch) =>
                setValues((current) => ({
                  ...current,
                  deliverables: current.deliverables.map((item) =>
                    item.id === id ? { ...item, ...patch } : item,
                  ),
                }))
              }
              onRemoveDeliverable={(id) =>
                setValues((current) => ({
                  ...current,
                  deliverables: current.deliverables.filter((item) => item.id !== id),
                }))
              }
              onAddType={(type) => {
                setValues((current) => addOrIncrementDeliverable(current, type));
                setTypePickerPlatform(null);
              }}
            />
          ))
        )}
      </div>
    );
  }

  return (
    <div className="space-y-5">
      <WizardStepper
        step={step}
        highestReached={highestReached}
        disabled={disabled}
        onGoTo={(next) => {
          setLocalErrors({});
          setStep(next);
        }}
      />

      <Card padding="default" className="sm:px-5 sm:py-5">
        <div className="mb-5">
          <h2 className="text-[1.125rem] font-semibold tracking-[-0.02em] text-primary">
            {stepMeta.title}
          </h2>
          <p className="mt-1 text-[0.875rem] text-ink-60">{stepMeta.subtitle}</p>
        </div>

        {stepContent}

        <div className="mt-6 flex flex-wrap gap-2 border-t border-line pt-4">
          <Button type="button" variant="secondary" size="sm" disabled={disabled} onClick={goBack}>
            Back
          </Button>
          <Button
            type="button"
            variant="secondary"
            size="sm"
            disabled={disabled}
            onClick={handleSaveDraft}
          >
            {busyAction === "draft" ? "Saving…" : "Save draft"}
          </Button>
          {step < 3 ? (
            <Button type="button" size="sm" disabled={disabled} onClick={goNext}>
              Continue
            </Button>
          ) : (
            <Button type="button" size="sm" disabled={disabled} onClick={handleCreate}>
              {busyAction === "active" ? "Creating…" : "Create Campaign"}
            </Button>
          )}
        </div>
      </Card>

      {pendingRemovePlatform ? (
        <div
          className="fixed inset-0 z-50 flex items-center justify-center bg-primary/40 px-4"
          role="dialog"
          aria-modal="true"
          aria-labelledby={`${formId}-remove-title`}
        >
          <Card className="w-full max-w-md" padding="default">
            <h3 id={`${formId}-remove-title`} className="text-[1rem] font-semibold text-primary">
              Remove {socialProviderLabel(pendingRemovePlatform)} deliverables?
            </h3>
            <p className="mt-2 text-[0.875rem] text-ink-60">
              Removing {socialProviderLabel(pendingRemovePlatform)} will remove the{" "}
              {socialProviderLabel(pendingRemovePlatform)} deliverables you&apos;ve configured from
              this campaign draft.
            </p>
            <div className="mt-4 flex flex-wrap gap-2">
              <Button
                type="button"
                variant="secondary"
                size="sm"
                onClick={() => setPendingRemovePlatform(null)}
              >
                Cancel
              </Button>
              <Button type="button" size="sm" onClick={confirmRemovePlatform}>
                Remove network
              </Button>
            </div>
          </Card>
        </div>
      ) : null}
    </div>
  );
}
