import { useCallback, useEffect, useMemo, useState, type FormEvent } from 'react';
import { getSikshyaApi } from '../api';
import { GatedFeatureWorkspace } from '../components/GatedFeatureWorkspace';
import { EmbeddableShell } from '../components/shared/EmbeddableShell';
import { ApiErrorPanel } from '../components/shared/ApiErrorPanel';
import { ButtonPrimary, ButtonSecondary } from '../components/shared/buttons';
import { ListPanel } from '../components/shared/list/ListPanel';
import { SkeletonCard } from '../components/shared/Skeleton';
import { useSikshyaDialog } from '../components/shared/SikshyaDialogContext';
import { TopRightToast, useTopRightToast } from '../components/shared/TopRightToast';
import { useAddonEnabled } from '../hooks/useAddons';
import { useAsyncData } from '../hooks/useAsyncData';
import { isFeatureEnabled, resolveGatedWorkspaceMode } from '../lib/licensing';
import type { SikshyaReactConfig } from '../types';
import { __, sprintf } from '../lib/i18n';

type ProviderId = 'mailchimp' | 'mailerlite' | 'brevo' | 'kit';
type FieldType = 'string' | 'password' | 'textarea' | 'bool' | 'int' | 'select' | 'csv' | 'mapping';
type TabId = 'setup' | 'rules' | 'logs' | 'tools';
type MappingRow = {
  provider: ProviderId;
  remote_field: string;
  source: string;
};
type FieldDef = {
  type: FieldType;
  label: string;
  default: unknown;
  help?: string;
  choices?: Record<string, string> | null;
  sources?: Record<string, string> | null;
  min?: number | null;
  max?: number | null;
};
type Schema = Record<string, FieldDef>;
type Resp = {
  ok?: boolean;
  addon?: string;
  options?: Record<string, unknown>;
  schema?: Schema;
};

type RuleRow = {
  id: number;
  name: string;
  description: string;
  is_active: number | boolean;
  priority: number;
  event_key: string;
  filters_json?: string | null;
  actions_json?: string | null;
  created_at?: string;
  updated_at?: string;
};

type LogRow = {
  id: number;
  job_id: number;
  rule_id: number;
  provider: string;
  event_key: string;
  user_id: number;
  course_id: number;
  status: string;
  http_code: number;
  error_code: string;
  error_message?: string | null;
  created_at?: string;
};

const BASE_FIELDS = ['api_key', 'audience_id'] as const;
const TOGGLE_FIELDS = ['double_opt_in', 'sync_on_enrollment', 'sync_on_completion'] as const;
const PROVIDER_ORDER: ProviderId[] = ['mailchimp', 'mailerlite', 'brevo', 'kit'];

const PROVIDER_COPY: Record<
  ProviderId,
  {
    name: string;
    badge: string;
    description: string;
    credentialLabel: string;
    credentialPlaceholder: string;
    listLabel: string;
    destinationPlaceholder: string;
    destinationHelp: string;
    mappingNoun: string;
    fieldLabel: string;
    fieldPlaceholder: string;
    fieldHint: string;
    beginnerTip: string;
    presets: Array<{ remote_field: string; source: string }>;
  }
> = {
  mailchimp: {
    name: 'Mailchimp',
    badge: 'Audience-based',
    description: 'Best when you already use Mailchimp audiences and merge tags for campaigns and automations.',
    credentialLabel: 'Mailchimp API key',
    credentialPlaceholder: 'abcd1234-us21',
    listLabel: 'Audience',
    destinationPlaceholder: 'Audience ID',
    destinationHelp: 'Find this in Audience -> Settings -> Audience name and defaults.',
    mappingNoun: 'merge fields',
    fieldLabel: 'Merge field tag',
    fieldPlaceholder: 'FNAME',
    fieldHint: 'Examples: `FNAME`, `LNAME`, `COURSE_NAME`, or any merge tag that already exists in your Mailchimp audience.',
    beginnerTip: 'Start simple: connect one audience, sync on enrollment, then map only FNAME and LNAME first.',
    presets: [
      { remote_field: 'FNAME', source: 'first_name' },
      { remote_field: 'LNAME', source: 'last_name' },
      { remote_field: 'COURSE', source: 'course_name' },
      { remote_field: 'EVENT', source: 'event' },
    ],
  },
  mailerlite: {
    name: 'MailerLite',
    badge: 'Simple groups',
    description: 'A clean beginner-friendly setup using one group plus optional custom fields.',
    credentialLabel: 'MailerLite API token',
    credentialPlaceholder: 'Paste your MailerLite API token',
    listLabel: 'Group',
    destinationPlaceholder: 'Group ID',
    destinationHelp: 'Open Subscribers -> Groups and copy the group ID you want learners added to.',
    mappingNoun: 'custom fields',
    fieldLabel: 'Custom field key',
    fieldPlaceholder: 'course_name',
    fieldHint: 'Examples: `name`, `course_name`, `course_id`, or your existing MailerLite custom field keys.',
    beginnerTip: 'MailerLite is usually the easiest first setup for noob users: one group, basic fields, done.',
    presets: [
      { remote_field: 'name', source: 'full_name' },
      { remote_field: 'course_name', source: 'course_name' },
      { remote_field: 'course_id', source: 'course_id' },
      { remote_field: 'event', source: 'event' },
    ],
  },
  brevo: {
    name: 'Brevo',
    badge: 'List + attributes',
    description: 'Great if your team already uses Brevo lists and created contact attributes inside Brevo.',
    credentialLabel: 'Brevo API key',
    credentialPlaceholder: 'Paste your Brevo API key',
    listLabel: 'List',
    destinationPlaceholder: 'List ID',
    destinationHelp: 'Use the numeric Brevo list ID. Mapped attributes must already exist in your Brevo account.',
    mappingNoun: 'contact attributes',
    fieldLabel: 'Brevo attribute key',
    fieldPlaceholder: 'FIRSTNAME',
    fieldHint: 'Examples: `FIRSTNAME`, `LASTNAME`, `COURSE_NAME`, `EVENT`. These attributes must already exist in Brevo.',
    beginnerTip: 'Before adding mappings in Brevo, create the matching contact attributes inside Brevo first.',
    presets: [
      { remote_field: 'FIRSTNAME', source: 'first_name' },
      { remote_field: 'LASTNAME', source: 'last_name' },
      { remote_field: 'COURSE_NAME', source: 'course_name' },
      { remote_field: 'EVENT', source: 'event' },
    ],
  },
  kit: {
    name: 'Kit (ConvertKit)',
    badge: 'Form-based',
    description: 'Use this when you want learners added to a Kit form and optionally enriched with existing custom fields.',
    credentialLabel: 'Kit API key',
    credentialPlaceholder: 'Paste your Kit API key',
    listLabel: 'Form',
    destinationPlaceholder: 'Form ID',
    destinationHelp: 'Use the Kit form ID you want new learners added to after subscriber upsert.',
    mappingNoun: 'custom fields',
    fieldLabel: 'Kit field name',
    fieldPlaceholder: 'first_name',
    fieldHint: 'Examples: `first_name`, `Last name`, `Course Name`, `Event`. Kit ignores custom fields that do not already exist.',
    beginnerTip: 'For Kit, confirm the basic form subscription first, then add custom fields only after that works.',
    presets: [
      { remote_field: 'first_name', source: 'first_name' },
      { remote_field: 'Last name', source: 'last_name' },
      { remote_field: 'Course Name', source: 'course_name' },
      { remote_field: 'Event', source: 'event' },
    ],
  },
};

function asProvider(value: unknown): ProviderId {
  if (value === 'mailerlite' || value === 'brevo' || value === 'kit') {
    return value;
  }
  return 'mailchimp';
}

function parseMappings(value: unknown): MappingRow[] {
  if (!Array.isArray(value)) {
    return [];
  }
  return value
    .filter((row): row is Record<string, unknown> => Boolean(row && typeof row === 'object'))
    .map((row) => ({
      provider: asProvider(row.provider),
      remote_field: typeof row.remote_field === 'string' ? row.remote_field : '',
      source: typeof row.source === 'string' ? row.source : '',
    }));
}

export function EmailMarketingPage(props: { config: SikshyaReactConfig; title: string; embedded?: boolean }) {
  const { config, title, embedded } = props;
  const addonId = 'email_marketing';
  const featureOk = isFeatureEnabled(config, addonId);
  const addon = useAddonEnabled(addonId);
  const mode = resolveGatedWorkspaceMode(featureOk, addon.enabled, addon.loading);
  const enabled = mode === 'full';
  const [tab, setTab] = useState<TabId>('setup');
  const [opts, setOpts] = useState<Record<string, unknown>>({});
  const [schema, setSchema] = useState<Schema>({});
  const [saving, setSaving] = useState(false);
  const toast = useTopRightToast();
  const dialog = useSikshyaDialog();
  const [toolUserId, setToolUserId] = useState('');
  const [toolCourseId, setToolCourseId] = useState('');
  const [toolBusy, setToolBusy] = useState(false);

  const loader = useCallback(async () => {
    if (!enabled) return { ok: true, options: {}, schema: {} } as Resp;
    return getSikshyaApi().get<Resp>(`/pro/addons/${encodeURIComponent(addonId)}/settings`);
  }, [enabled, addonId]);
  const { loading, data, error, refetch } = useAsyncData(loader, [enabled, addonId]);

  useEffect(() => {
    if (data?.options) setOpts({ ...data.options });
    if (data?.schema) setSchema(data.schema);
  }, [data]);

  const rulesLoader = useCallback(async () => {
    if (!enabled) return { ok: true, rules: [] as RuleRow[] };
    return getSikshyaApi().get<{ ok?: boolean; rules?: RuleRow[]; message?: string }>(`/pro/email-marketing/rules`);
  }, [enabled]);
  const logsLoader = useCallback(async () => {
    if (!enabled) return { ok: true, logs: [] as LogRow[], total: 0, page: 1, per_page: 50, total_pages: 1 };
    return getSikshyaApi().get<{
      ok?: boolean;
      logs?: LogRow[];
      total?: number;
      page?: number;
      per_page?: number;
      total_pages?: number;
    }>(`/pro/email-marketing/logs?per_page=50&page=1`);
  }, [enabled]);

  const {
    loading: rulesLoading,
    data: rulesData,
    error: rulesError,
    refetch: refetchRules,
  } = useAsyncData(rulesLoader, [enabled]);
  const {
    loading: logsLoading,
    data: logsData,
    error: logsError,
    refetch: refetchLogs,
  } = useAsyncData(logsLoader, [enabled]);

  const rules = useMemo(() => (Array.isArray(rulesData?.rules) ? rulesData?.rules || [] : []), [rulesData]);
  const logs = useMemo(() => (Array.isArray(logsData?.logs) ? logsData?.logs || [] : []), [logsData]);

  const provider = asProvider(opts.provider);
  const providerCopy = PROVIDER_COPY[provider];
  const sourceChoices = schema.field_mappings?.sources || {};
  const mappings = useMemo(() => parseMappings(opts.field_mappings), [opts.field_mappings]);
  const providerMappings = useMemo(() => mappings.filter((row) => row.provider === provider), [mappings, provider]);

  const setField = (name: string, value: unknown) => setOpts((prev) => ({ ...prev, [name]: value }));
  const setMappingsForProvider = (nextRows: MappingRow[]) =>
    setOpts((prev) => {
      const otherRows = parseMappings(prev.field_mappings).filter((row) => row.provider !== provider);
      return { ...prev, field_mappings: [...otherRows, ...nextRows] };
    });

  const updateProviderMapping = (index: number, patch: Partial<MappingRow>) => {
    const next = providerMappings.map((row, rowIndex) => (rowIndex === index ? { ...row, ...patch, provider } : row));
    setMappingsForProvider(next);
  };

  const addMapping = (preset?: Partial<MappingRow>) => {
    setMappingsForProvider([
      ...providerMappings,
      {
        provider,
        remote_field: preset?.remote_field || '',
        source: preset?.source || 'first_name',
      },
    ]);
  };

  const removeMapping = (index: number) => {
    setMappingsForProvider(providerMappings.filter((_, rowIndex) => rowIndex !== index));
  };

  const hasPreset = (remoteField: string) =>
    providerMappings.some((row) => row.remote_field.trim().toLowerCase() === remoteField.trim().toLowerCase());

  const onSave = async (e: FormEvent) => {
    e.preventDefault();
    setSaving(true);
    try {
      await getSikshyaApi().post(`/pro/addons/${encodeURIComponent(addonId)}/settings`, opts);
      toast.success(__('Saved', 'sikshya'), 'Settings saved.');
      void refetch();
    } catch (err) {
      toast.error(__('Save failed', 'sikshya'), err instanceof Error ? err.message : 'Save failed');
    } finally {
      setSaving(false);
    }
  };

  const renderInputField = (name: (typeof BASE_FIELDS)[number]) => {
    const def = schema[name];
    if (!def) {
      return null;
    }
    const value = opts[name];
    const inputClass =
      'mt-1 w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm dark:border-slate-700 dark:bg-slate-950';

    return (
      <label key={name} className="block text-sm">
        <span className="font-medium text-slate-900 dark:text-white">
          {name === 'api_key' ? providerCopy.credentialLabel : `${providerCopy.listLabel} ID`}
        </span>
        <input
          type={def.type === 'password' ? __('password', 'sikshya') : __('text', 'sikshya')}
          autoComplete={def.type === 'password' ? 'new-password' : undefined}
          value={typeof value === 'string' ? value : ''}
          onChange={(e) => setField(name, e.target.value)}
          className={inputClass}
          placeholder={name === 'api_key' ? providerCopy.credentialPlaceholder : providerCopy.destinationPlaceholder}
        />
        <span className="mt-1 block text-xs text-slate-500 dark:text-slate-400">
          {name === 'api_key' ? def.help : providerCopy.destinationHelp}
        </span>
      </label>
    );
  };

  const renderToggleField = (name: (typeof TOGGLE_FIELDS)[number]) => {
    const def = schema[name];
    if (!def) {
      return null;
    }
    return (
      <label key={name} className="flex items-start gap-3 text-sm">
        <input
          type="checkbox"
          checked={Boolean(opts[name])}
          onChange={(e) => setField(name, e.target.checked)}
          className="mt-1 h-4 w-4 rounded border-slate-300 text-brand-600 focus:ring-brand-500 dark:border-slate-600 dark:bg-slate-900"
        />
        <span>
          <span className="font-medium text-slate-900 dark:text-white">{def.label}</span>
          {def.help ? <span className="block text-xs text-slate-500 dark:text-slate-400">{def.help}</span> : null}
        </span>
      </label>
    );
  };

  const createDefaultRule = async (event_key: string) => {
    toast.clear();
    try {
      const payload: Record<string, unknown> = {
        name: event_key.replace(/_/g, ' '),
        description: '',
        is_active: true,
        priority: 100,
        event_key,
        filters: { course: { mode: 'any', ids: [] as number[] } },
        actions: { upsert: true, tags_add: [event_key] },
      };
      await getSikshyaApi().post(`/pro/email-marketing/rules`, payload);
      toast.success(__('Created', 'sikshya'), 'Rule created.');
      void refetchRules();
      setTab('rules');
    } catch (err) {
      toast.error(__('Create failed', 'sikshya'), err instanceof Error ? err.message : 'Could not create rule');
    }
  };

  const runToolTest = async () => {
    toast.clear();
    setToolBusy(true);
    try {
      const user_id = Number(toolUserId) || 0;
      const course_id = Number(toolCourseId) || 0;
      if (!user_id) {
        throw new Error(__('User ID is required.', 'sikshya'));
      }
      await getSikshyaApi().post(`/pro/email-marketing/tools/test`, {
        user_id,
        course_id,
        event_key: 'sikshya_user_enrolled',
      });
      toast.success(__('Queued', 'sikshya'), 'Test queued (if consent + rule match).');
      setTab('logs');
      void refetchLogs();
    } catch (err) {
      toast.error(__('Tool failed', 'sikshya'), err instanceof Error ? err.message : 'Tool failed');
    } finally {
      setToolBusy(false);
    }
  };

  const runToolBackfill = async () => {
    toast.clear();
    setToolBusy(true);
    try {
      const course_id = Number(toolCourseId) || 0;
      const res = await getSikshyaApi().post<{ ok?: boolean; queued?: number }>(`/pro/email-marketing/tools/backfill`, {
        course_id,
        max: 200,
        days: 365,
      });
      toast.success(__('Queued', 'sikshya'), `Backfill queued ${res?.queued ?? 0} enrollments.`);
      setTab('logs');
      void refetchLogs();
    } catch (err) {
      toast.error(__('Backfill failed', 'sikshya'), err instanceof Error ? err.message : 'Backfill failed');
    } finally {
      setToolBusy(false);
    }
  };

  return (
    <EmbeddableShell
      embedded={embedded}
      config={config}
      title={title}
      subtitle={__('Sync learners into your email marketing provider when they enroll or complete courses.', 'sikshya')}
    >
      <TopRightToast toast={toast.toast} onDismiss={toast.clear} />
      <GatedFeatureWorkspace
        mode={mode}
        featureId={addonId}
        config={config}
        featureTitle={__('Email marketing', 'sikshya')}
        featureDescription={__('Native Mailchimp, MailerLite, Brevo, and Kit sync. Sikshya will upsert subscribers, attach list membership, and map learner/course data into provider fields.', 'sikshya')}
        previewVariant="form"
        addonEnableTitle={__('Email marketing is not enabled', 'sikshya')}
        addonEnableDescription={__('Turn on the Email marketing add-on to configure provider sync and beginner-friendly setup.', 'sikshya')}
        canEnable={Boolean(addon.licenseOk)}
        enableBusy={addon.loading}
        onEnable={() => addon.enable()}
        addonError={addon.error}
      >
        <div className="space-y-6">
          <div className="flex flex-wrap gap-2">
            <ButtonSecondary type="button" className={tab === 'setup' ? 'ring-2 ring-brand-500/40' : ''} onClick={() => setTab('setup')}>
              Setup
            </ButtonSecondary>
            <ButtonSecondary type="button" className={tab === 'rules' ? 'ring-2 ring-brand-500/40' : ''} onClick={() => setTab('rules')}>
              Rules
            </ButtonSecondary>
            <ButtonSecondary type="button" className={tab === 'logs' ? 'ring-2 ring-brand-500/40' : ''} onClick={() => setTab('logs')}>
              Logs
            </ButtonSecondary>
            <ButtonSecondary type="button" className={tab === 'tools' ? 'ring-2 ring-brand-500/40' : ''} onClick={() => setTab('tools')}>
              Tools
            </ButtonSecondary>
          </div>

          {tab === 'setup' ? (
            <>
              {error ? <ApiErrorPanel error={error} title={__('Could not load settings', 'sikshya')} onRetry={() => refetch()} /> : null}

              <ListPanel className="p-6">
                <div className="grid items-start gap-5 xl:grid-cols-[minmax(0,1.35fr)_minmax(18rem,0.65fr)]">
                  <div>
                    <h2 className="text-base font-semibold text-slate-900 dark:text-white">{__('Beginner-friendly setup', 'sikshya')}</h2>
                    <p className="mt-1 text-sm text-slate-500 dark:text-slate-400">
                      Choose the provider your team already uses, paste the two values it asks for, enable sync, then add field mappings only if you need extra data.
                    </p>
                    <div className="mt-4 grid gap-3 md:grid-cols-2">
                      {PROVIDER_ORDER.map((id) => {
                        const info = PROVIDER_COPY[id];
                        const active = provider === id;
                        return (
                          <button
                            key={id}
                            type="button"
                            onClick={() => setField('provider', id)}
                            className={`rounded-2xl border p-4 text-left transition ${
                              active
                                ? 'border-brand-500 bg-brand-50 ring-2 ring-brand-500/20 dark:bg-brand-950/30'
                                : 'border-slate-200 bg-white hover:border-slate-300 dark:border-slate-700 dark:bg-slate-900'
                            }`}
                          >
                            <div className="flex items-start justify-between gap-3">
                              <div>
                                <div className="text-sm font-semibold text-slate-900 dark:text-white">{info.name}</div>
                                <div className="mt-1 text-xs text-slate-500 dark:text-slate-400">{info.description}</div>
                              </div>
                              <span className="shrink-0 rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold uppercase tracking-wide text-slate-600 dark:bg-slate-800 dark:text-slate-300">
                                {info.badge}
                              </span>
                            </div>
                          </button>
                        );
                      })}
                    </div>
                  </div>

                  <div className="rounded-2xl border border-brand-100 bg-brand-50/60 p-5 text-sm text-brand-900 dark:border-brand-900/40 dark:bg-brand-950/40 dark:text-brand-200">
                    <div className="text-sm font-semibold">{__('Recommended flow', 'sikshya')}</div>
                    <ol className="mt-3 space-y-2 text-xs leading-relaxed">
                      <li>1. Pick one provider only.</li>
                      <li>2. Paste the API key and destination ID.</li>
                      <li>3. Turn on enrollment sync first.</li>
                      <li>4. Save, test with one learner, then add mappings.</li>
                    </ol>
                    <p className="mt-3 rounded-xl bg-white/70 px-3 py-2 text-xs dark:bg-slate-900/40">{providerCopy.beginnerTip}</p>
                  </div>
                </div>
              </ListPanel>

              <ListPanel className="p-6">
                {loading ? (
                  <SkeletonCard rows={7} />
                ) : (
                  <form onSubmit={onSave} className="space-y-6">
                <div className="rounded-2xl border border-slate-200 bg-white p-5 dark:border-slate-700 dark:bg-slate-950/40">
                  <div className="flex items-center justify-between gap-3">
                    <div>
                      <h2 className="text-sm font-semibold text-slate-900 dark:text-white">1. Connect {providerCopy.name}</h2>
                      <p className="mt-1 text-xs text-slate-500 dark:text-slate-400">
                        Paste the credentials and the exact audience, group, list, or form destination where learners should be added.
                      </p>
                    </div>
                    <span className="rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-xs font-semibold text-slate-600 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-300">
                      {providerCopy.listLabel}-based sync
                    </span>
                  </div>
                  <div className="mt-4 grid gap-4 sm:grid-cols-2">{BASE_FIELDS.map((name) => renderInputField(name))}</div>
                </div>

                <div className="space-y-3 rounded-2xl border border-slate-100 bg-slate-50 p-5 dark:border-slate-800 dark:bg-slate-900/60">
                  <div>
                    <h2 className="text-sm font-semibold text-slate-900 dark:text-white">2. Choose when to sync</h2>
                    <p className="mt-1 text-xs text-slate-500 dark:text-slate-400">
                      Keep this simple at first. Most noob users start with enrollment sync and only add completion sync later.
                    </p>
                  </div>
                  {TOGGLE_FIELDS.map((name) => renderToggleField(name))}
                </div>

                <div className="rounded-2xl border border-slate-200 bg-white p-5 dark:border-slate-700 dark:bg-slate-950/40">
                  <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
                    <div>
                      <h2 className="text-sm font-semibold text-slate-900 dark:text-white">3. {schema.field_mappings?.label || 'List field mappings'}</h2>
                      <p className="mt-1 text-xs text-slate-500 dark:text-slate-400">
                        Map Sikshya fields into your {providerCopy.listLabel.toLowerCase()} {providerCopy.mappingNoun}. Skip this until after your first successful sync if you want the easiest setup.
                      </p>
                    </div>
                    <ButtonSecondary onClick={() => addMapping()}>{__('Add mapping', 'sikshya')}</ButtonSecondary>
                  </div>

                  <div className="mt-4 rounded-xl border border-brand-100 bg-brand-50/60 p-4 text-xs text-brand-900 dark:border-brand-900/40 dark:bg-brand-950/40 dark:text-brand-200">
                    <p className="font-medium">
                      {providerCopy.name} {providerCopy.mappingNoun}
                    </p>
                    <p className="mt-1">{providerCopy.fieldHint}</p>
                  </div>

                  <div className="mt-4 flex flex-wrap gap-2">
                    {providerCopy.presets.map((preset) => (
                      <button
                        key={`${provider}-${preset.remote_field}`}
                        type="button"
                        className="rounded-full border border-slate-200 bg-slate-50 px-3 py-1.5 text-xs font-medium text-slate-700 hover:bg-slate-100 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:hover:bg-slate-800"
                        disabled={hasPreset(preset.remote_field)}
                        onClick={() => addMapping(preset)}
                      >
                        Add {preset.remote_field}
                      </button>
                    ))}
                  </div>

                  <div className="mt-5 space-y-3">
                    {providerMappings.length ? (
                      providerMappings.map((row, index) => (
                        <div
                          key={`${provider}-${index}`}
                          className="grid gap-3 rounded-xl border border-slate-200 bg-slate-50/70 p-4 dark:border-slate-700 dark:bg-slate-900/60 lg:grid-cols-[minmax(0,1.2fr)_minmax(0,1fr)_auto]"
                        >
                          <label className="block text-sm">
                            <span className="font-medium text-slate-900 dark:text-white">{providerCopy.fieldLabel}</span>
                            <input
                              type="text"
                              value={row.remote_field}
                              onChange={(e) => updateProviderMapping(index, { remote_field: e.target.value })}
                              className="mt-1 block w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-600 dark:bg-slate-800 dark:text-white dark:placeholder:text-slate-500"
                              placeholder={providerCopy.fieldPlaceholder}
                            />
                          </label>

                          <label className="block text-sm">
                            <span className="font-medium text-slate-900 dark:text-white">
                              {sprintf(__('%s source', 'sikshya'), 'Sikshya')}
                            </span>
                            <select
                              value={row.source}
                              onChange={(e) => updateProviderMapping(index, { source: e.target.value })}
                              className="mt-1 block w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-600 dark:bg-slate-800 dark:text-white dark:placeholder:text-slate-500"
                            >
                              {Object.entries(sourceChoices).map(([source, label]) => (
                                <option key={source} value={source}>
                                  {label}
                                </option>
                              ))}
                            </select>
                          </label>

                          <div className="flex items-end">
                            <button
                              type="button"
                              className="rounded-lg px-3 py-2 text-sm font-medium text-rose-700 hover:bg-rose-50 dark:text-rose-300 dark:hover:bg-rose-950/30"
                              onClick={() => removeMapping(index)}
                            >
                              Remove
                            </button>
                          </div>
                        </div>
                      ))
                    ) : (
                      <div className="rounded-xl border border-dashed border-slate-300 bg-slate-50 px-4 py-5 text-sm text-slate-500 dark:border-slate-700 dark:bg-slate-900/40 dark:text-slate-400">
                        No {providerCopy.mappingNoun} mapped yet. Add mappings only if your destination expects extra fields like course name, event, or learner names.
                      </div>
                    )}
                  </div>
                </div>

                <div className="flex items-center gap-3">
                  <ButtonPrimary type="submit" disabled={saving}>
                    {saving ? __('Saving…', 'sikshya') : __('4. Save settings', 'sikshya')}
                  </ButtonPrimary>
                </div>
                  </form>
                )}
              </ListPanel>

              <ListPanel className="p-6">
                <h2 className="text-sm font-semibold text-slate-900 dark:text-white">{__('Next steps', 'sikshya')}</h2>
                <ul className="mt-3 space-y-2 text-sm">
                  <li className="text-slate-700 dark:text-slate-200">
                    Mailchimp: find your Audience ID in <span className="font-medium">Audience {'->'} Settings {'->'} Audience name and defaults</span>.
                  </li>
                  <li className="text-slate-700 dark:text-slate-200">
                    MailerLite: find your Group ID in <span className="font-medium">Subscribers {'->'} Groups</span>.
                  </li>
                  <li className="text-slate-700 dark:text-slate-200">Brevo: use the numeric List ID and create any mapped contact attributes in Brevo first.</li>
                  <li className="text-slate-700 dark:text-slate-200">Kit: use a Form ID and remember Kit ignores custom fields that do not already exist.</li>
                  <li className="text-slate-700 dark:text-slate-200">
                    After saving, enroll one test learner and confirm the record lands in the right destination before adding more mappings.
                  </li>
                </ul>
              </ListPanel>
            </>
          ) : null}

          {tab === 'rules' ? (
            <ListPanel className="p-6">
              {rulesError ? <ApiErrorPanel error={rulesError} title={__('Could not load rules', 'sikshya')} onRetry={() => refetchRules()} /> : null}
              <div className="flex flex-wrap items-start justify-between gap-3">
                <div>
                  <h2 className="text-base font-semibold text-slate-900 dark:text-white">{__('Rules', 'sikshya')}</h2>
                  <p className="mt-1 text-sm text-slate-500 dark:text-slate-400">
                    Define what to do when events happen. Start with one enrollment rule, confirm it works, then add completion or order rules.
                  </p>
                </div>
                <div className="flex flex-wrap gap-2">
                  <ButtonSecondary type="button" onClick={() => void createDefaultRule('sikshya_user_enrolled')}>
                    + Enrollment rule
                  </ButtonSecondary>
                  <ButtonSecondary type="button" onClick={() => void createDefaultRule('sikshya_course_completed')}>
                    + Completion rule
                  </ButtonSecondary>
                  <ButtonSecondary type="button" onClick={() => void createDefaultRule('sikshya_order_fulfilled')}>
                    + Order fulfilled rule
                  </ButtonSecondary>
                </div>
              </div>

              {rulesLoading ? (
                <div className="mt-5">
                  <SkeletonCard rows={6} />
                </div>
              ) : rules.length ? (
                <ul className="mt-5 space-y-3">
                  {rules.map((r) => {
                    const on = Boolean(r.is_active);
                    return (
                      <li key={r.id} className="rounded-2xl border border-slate-200 bg-white p-5 dark:border-slate-700 dark:bg-slate-950/40">
                        <div className="flex flex-wrap items-start justify-between gap-3">
                          <div className="min-w-0">
                            <div className="flex flex-wrap items-center gap-2">
                              <span className="text-sm font-semibold text-slate-900 dark:text-white">{r.name || r.event_key}</span>
                              <span
                                className={`rounded-full px-2.5 py-1 text-xs font-semibold uppercase tracking-wide ${
                                  on
                                    ? 'bg-emerald-100 text-emerald-800 dark:bg-emerald-950/40 dark:text-emerald-200'
                                    : 'bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-300'
                                }`}
                              >
                                {on ? __('Active', 'sikshya') : __('Off', 'sikshya')}
                              </span>
                              <span className="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold uppercase tracking-wide text-slate-600 dark:bg-slate-800 dark:text-slate-300">
                                {r.event_key}
                              </span>
                            </div>
                            {r.description ? <p className="mt-1 text-sm text-slate-600 dark:text-slate-300">{r.description}</p> : null}
                            <p className="mt-2 text-xs text-slate-500 dark:text-slate-400">
                              Priority: <span className="font-medium text-slate-700 dark:text-slate-200">{r.priority}</span>
                            </p>
                          </div>
                          <div className="flex shrink-0 flex-wrap gap-2">
                            <ButtonSecondary
                              type="button"
                              onClick={() => {
                                const next = { ...r, is_active: !on };
                                void (async () => {
                                  try {
                                    await getSikshyaApi().patch(`/pro/email-marketing/rules/${encodeURIComponent(String(r.id))}`, {
                                      is_active: !on,
                                      name: next.name,
                                      description: next.description,
                                      priority: next.priority,
                                      event_key: next.event_key,
                                      filters_json: next.filters_json ?? null,
                                      actions_json: next.actions_json ?? null,
                                    });
                                    void refetchRules();
                                  } catch (err) {
                                    toast.error(__('Update failed', 'sikshya'), err instanceof Error ? err.message : 'Update failed');
                                  }
                                })();
                              }}
                            >
                              {on ? __('Disable', 'sikshya') : __('Enable', 'sikshya')}
                            </ButtonSecondary>
                            <ButtonSecondary
                              type="button"
                              onClick={() => {
                                void (async () => {
                                  const ok = await dialog.confirm({
                                    title: __('Delete this rule?', 'sikshya'),
                                    message: __('This automation rule will be permanently removed.', 'sikshya'),
                                    confirmLabel: __('Delete', 'sikshya'),
                                    variant: 'danger',
                                  });
                                  if (!ok) return;
                                  try {
                                    await getSikshyaApi().delete(`/pro/email-marketing/rules/${encodeURIComponent(String(r.id))}`);
                                    void refetchRules();
                                  } catch (err) {
                                    toast.error(__('Delete failed', 'sikshya'), err instanceof Error ? err.message : 'Delete failed');
                                  }
                                })();
                              }}
                            >
                              Delete
                            </ButtonSecondary>
                          </div>
                        </div>
                      </li>
                    );
                  })}
                </ul>
              ) : (
                <div className="mt-5 rounded-2xl border border-dashed border-slate-300 bg-slate-50 px-5 py-6 text-sm text-slate-600 dark:border-slate-700 dark:bg-slate-900/40 dark:text-slate-300">
                  No rules yet. Add an enrollment rule to get started.
                </div>
              )}
            </ListPanel>
          ) : null}

          {tab === 'logs' ? (
            <ListPanel className="p-6">
              {logsError ? <ApiErrorPanel error={logsError} title={__('Could not load logs', 'sikshya')} onRetry={() => refetchLogs()} /> : null}
              <div className="flex flex-wrap items-start justify-between gap-3">
                <div>
                  <h2 className="text-base font-semibold text-slate-900 dark:text-white">{__('Logs', 'sikshya')}</h2>
                  <p className="mt-1 text-sm text-slate-500 dark:text-slate-400">
                    Delivery history for provider calls. This becomes more useful once the queue runner is enabled.
                  </p>
                </div>
                <ButtonSecondary type="button" onClick={() => refetchLogs()}>
                  Refresh
                </ButtonSecondary>
              </div>

              {logsLoading ? (
                <div className="mt-5">
                  <SkeletonCard rows={6} />
                </div>
              ) : logs.length ? (
                <div className="mt-5 overflow-hidden rounded-2xl border border-slate-200 bg-white dark:border-slate-700 dark:bg-slate-950/40">
                  <table className="w-full text-left text-sm">
                    <thead className="bg-slate-50 text-xs uppercase tracking-wide text-slate-600 dark:bg-slate-900/60 dark:text-slate-300">
                      <tr>
                        <th className="px-4 py-3">{__('When', 'sikshya')}</th>
                        <th className="px-4 py-3">{__('Event', 'sikshya')}</th>
                        <th className="px-4 py-3">{__('Provider', 'sikshya')}</th>
                        <th className="px-4 py-3">{__('Status', 'sikshya')}</th>
                        <th className="px-4 py-3">{__('HTTP', 'sikshya')}</th>
                        <th className="px-4 py-3">{__('User', 'sikshya')}</th>
                        <th className="px-4 py-3">{__('Course', 'sikshya')}</th>
                      </tr>
                    </thead>
                    <tbody className="divide-y divide-slate-200 dark:divide-slate-800">
                      {logs.map((l) => (
                        <tr key={l.id} className="text-slate-800 dark:text-slate-100">
                          <td className="px-4 py-3 text-xs text-slate-500 dark:text-slate-400">{l.created_at || ''}</td>
                          <td className="px-4 py-3">
                            <span className="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold uppercase tracking-wide text-slate-700 dark:bg-slate-800 dark:text-slate-200">
                              {l.event_key}
                            </span>
                          </td>
                          <td className="px-4 py-3">{l.provider}</td>
                          <td className="px-4 py-3">
                            <span className="font-medium">{l.status}</span>
                            {l.error_message ? <div className="mt-1 text-xs text-rose-600 dark:text-rose-300">{l.error_message}</div> : null}
                          </td>
                          <td className="px-4 py-3">{l.http_code || ''}</td>
                          <td className="px-4 py-3">{l.user_id}</td>
                          <td className="px-4 py-3">{l.course_id}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              ) : (
                <div className="mt-5 rounded-2xl border border-dashed border-slate-300 bg-slate-50 px-5 py-6 text-sm text-slate-600 dark:border-slate-700 dark:bg-slate-900/40 dark:text-slate-300">
                  No logs yet.
                </div>
              )}
            </ListPanel>
          ) : null}

          {tab === 'tools' ? (
            <ListPanel className="p-6">
              <h2 className="text-base font-semibold text-slate-900 dark:text-white">{__('Tools', 'sikshya')}</h2>
              <p className="mt-1 text-sm text-slate-500 dark:text-slate-400">
                Test sync and bulk operations. These respect consent and per-course overrides.
              </p>
              <div className="mt-5 grid gap-3 md:grid-cols-2">
                <div className="rounded-2xl border border-slate-200 bg-white p-5 text-sm dark:border-slate-700 dark:bg-slate-950/40">
                  <div className="font-semibold text-slate-900 dark:text-white">{__('Test sync (safe)', 'sikshya')}</div>
                  <p className="mt-1 text-slate-600 dark:text-slate-300">
                    Queues a test run for one user (and optional course). If there is no matching rule or the user is not opted-in, nothing is sent.
                  </p>
                  <div className="mt-4 grid gap-3 sm:grid-cols-2">
                    <label className="block text-sm">
                      <span className="font-medium text-slate-900 dark:text-white">{__('User ID', 'sikshya')}</span>
                      <input
                        className="mt-1 block w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-600 dark:bg-slate-800 dark:text-white dark:placeholder:text-slate-500"
                        value={toolUserId}
                        onChange={(e) => setToolUserId(e.target.value)}
                        placeholder={__('e.g. 123', 'sikshya')}
                      />
                    </label>
                    <label className="block text-sm">
                      <span className="font-medium text-slate-900 dark:text-white">{__('Course ID (optional)', 'sikshya')}</span>
                      <input
                        className="mt-1 block w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-600 dark:bg-slate-800 dark:text-white dark:placeholder:text-slate-500"
                        value={toolCourseId}
                        onChange={(e) => setToolCourseId(e.target.value)}
                        placeholder={__('e.g. 456', 'sikshya')}
                      />
                    </label>
                  </div>
                  <div className="mt-4 flex flex-wrap gap-2">
                    <ButtonPrimary type="button" disabled={toolBusy} onClick={() => void runToolTest()}>
                      {toolBusy ? __('Working…', 'sikshya') : __('Queue test', 'sikshya')}
                    </ButtonPrimary>
                  </div>
                </div>

                <div className="rounded-2xl border border-slate-200 bg-white p-5 text-sm dark:border-slate-700 dark:bg-slate-950/40">
                  <div className="font-semibold text-slate-900 dark:text-white">{__('Backfill enrollments', 'sikshya')}</div>
                  <p className="mt-1 text-slate-600 dark:text-slate-300">
                    Queues sync jobs for recent enrollments. Use after you create your first enrollment rule.
                  </p>
                  <div className="mt-4">
                    <label className="block text-sm">
                      <span className="font-medium text-slate-900 dark:text-white">{__('Course ID (optional)', 'sikshya')}</span>
                      <input
                        className="mt-1 block w-full rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-600 dark:bg-slate-800 dark:text-white dark:placeholder:text-slate-500"
                        value={toolCourseId}
                        onChange={(e) => setToolCourseId(e.target.value)}
                        placeholder={__('Leave empty for recent site-wide enrollments', 'sikshya')}
                      />
                    </label>
                  </div>
                  <div className="mt-4 flex flex-wrap gap-2">
                    <ButtonSecondary type="button" disabled={toolBusy} onClick={() => void runToolBackfill()}>
                      {toolBusy ? __('Working…', 'sikshya') : __('Queue backfill (last 365 days)', 'sikshya')}
                    </ButtonSecondary>
                  </div>
                </div>
              </div>
            </ListPanel>
          ) : null}
        </div>
      </GatedFeatureWorkspace>
    </EmbeddableShell>
  );
}

