/**
 * The Company ID action rail. Top card: the four numbered setup steps toward
 * a profitable niche, the Recomaze Copilot pointer and the fast-track actions
 * (cheat sheet download, extract from Claude / ChatGPT). Bottom card: the
 * Source material the record was learned from, with inline Upload / Paste and
 * the share (PDF) export.
 */

import { Link } from 'react-router-dom';
import React, { useEffect, useRef, useState } from 'react';
import {
  LuCheck,
  LuClipboardPaste,
  LuEye,
  LuFileText,
  LuListChecks,
  LuLock,
  LuRefreshCw,
  LuShare2,
  LuSparkles,
  LuUpload,
} from 'react-icons/lu';

import { ChatGptLogo } from '../icons/chatgpt-logo';
import { ClaudeLogo } from '../icons/claude-logo';
import { CompanyIdVisibilityPush } from '../../service/company-id/company-id.interface';
import { DocumentFile } from '../../types/documentation';

import { EXTRACT_ASSISTANT, ExtractAssistant } from './extract-modal';
import { agoLabel } from './field-row';
import {
  MODAL_GHOST_BUTTON_CLASS,
  MODAL_PRIMARY_BUTTON_CLASS,
} from './modal-buttons';

/** Join truthy class fragments; local since the repo has no cn helper. */
const cx = (...parts: Array<string | false | null | undefined>): string =>
  parts.filter(Boolean).join(' ');

const RAIL_DOCUMENTS_SHOWN = 4;

const EXTRACT_LOCK_HINT = 'Available on paid plans starting at $39';
const EXTRACT_FAST_TRACKS = [
  {
    assistant: EXTRACT_ASSISTANT.CLAUDE,
    icon: <ClaudeLogo size={14} />,
    label: 'Extract it from your Claude',
  },
  {
    assistant: EXTRACT_ASSISTANT.CHATGPT,
    icon: <ChatGptLogo size={14} />,
    label: 'Extract it from your ChatGPT',
  },
] as const;

export type UploadPhase = 'idle' | 'uploading' | 'processing' | 'pushing';

const UPLOAD_LABELS: Record<UploadPhase, string> = {
  idle: 'Upload',
  uploading: 'Uploading...',
  processing: 'Processing...',
  pushing: 'Publishing...',
};

const CARD_CLASS = 'rounded-[14px] border border-[#e1e3e5] bg-white';
const KICKER_CLASS =
  'font-mono text-[10.5px] font-medium uppercase tracking-[.08em] text-[#202223]';
const STEP_BUTTON_CLASS =
  'flex min-h-[38px] w-full cursor-pointer items-center gap-2 rounded-[10px] border border-[#e1e3e5] bg-[#f6f6f7] px-3 text-left text-[13px] font-medium text-[#202223] disabled:cursor-not-allowed disabled:bg-[#f6f6f7] disabled:text-[#a1a3a5] disabled:border-[#eaeaea]';
// The CURRENT step carries the gradient fill (the highlight travels with the
// merchant's progress instead of sitting on step 2 forever).
const STEP_BUTTON_CURRENT =
  'border-transparent text-white [background:linear-gradient(135deg,#C8175D,#7B3FE4)]';
const FAST_TRACK_CLASS =
  'flex min-h-[38px] w-full cursor-pointer items-center gap-2 rounded-[10px] border border-[#e1e3e5] bg-transparent px-3 text-left text-[13px] text-[#4a4d4f] no-underline disabled:opacity-70';
// Labels WRAP inside their pill rather than truncate: the rail is a fixed
// 300px and "What Gemini and ChatGPT say" - the step merchants understand
// least - lost its last word to an ellipsis. min-w-0 keeps the trailing lock
// from being pushed past the rounded border.
const ACTION_LABEL_CLASS = 'min-w-0 flex-1 leading-snug';
const DASHED_BUTTON_CLASS =
  'flex h-8 flex-1 cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-[9px] border border-dashed border-[#c9cccf] bg-transparent text-xs text-[#6d7175]';
const RAIL_INPUT_CLASS =
  'box-border w-full rounded-lg border border-[#e1e3e5] bg-white px-2.5 py-2 text-[12.5px] leading-normal text-[#202223] outline-none';

interface SourceMaterialRailProps {
  domain: string;
  populatedAt: string | null;
  documents: DocumentFile[];
  uploadPhase: UploadPhase;
  onUploadFiles: (files: FileList) => void;
  onPasteText: (title: string, text: string) => void;
  pasteSubmittedCount: number;
  kbBusy: boolean;
  exportBusy: boolean;
  onExportPdf: () => void;
  busyMode: 'site' | 'web' | null;
  onPopulate: (mode: 'site' | 'web') => void;
  pushBusy: boolean;
  onPushToVisibility: () => Promise<CompanyIdVisibilityPush | null>;
  /** Step 2 done: a "Search with AI" read completed at least once (record
   * stamp), or engine proposals are currently waiting. */
  enginesReadDone: boolean;
  /** Step 3 done: every Core ring field is claimed as Yours. */
  coreComplete: boolean;
  /** Core fields still unclaimed, shown on step 3 so "not done yet" comes
   * with a number instead of leaving the merchant hunting the ring. */
  coreRemaining: number;
  pushedOnce: boolean;
  /** Jump at the first Core answer still missing (step 3). */
  onGoToCore: () => void;
  canDownloadCheatSheet: boolean;
  canExtract: boolean;
  cheatSheetBusy: boolean;
  onDownloadCheatSheet: () => void;
  onOpenExtract: (assistant: ExtractAssistant) => void;
}

function railDocuments(documents: DocumentFile[]): DocumentFile[] {
  const ranked = [...documents].sort((first, second) => {
    const manualDelta =
      Number(second.source !== 'auto') - Number(first.source !== 'auto');
    if (manualDelta !== 0) return manualDelta;

    return (second.processed_at || '').localeCompare(first.processed_at || '');
  });

  return ranked.slice(0, RAIL_DOCUMENTS_SHOWN);
}

/**
 * Stepper badge in the left gutter: a green check once the step is done
 * (the step stays rerunnable), the brand-filled number on the current step,
 * an outlined faint number while the step is locked. Sitting outside the
 * button, it keeps full contrast even when a locked button renders dimmed -
 * the numbered chain is what tells the merchant this is a one-way sequence.
 *
 * @param {{ number: number; done: boolean; current: boolean }} props - The
 *   step's one-based position and state.
 * @returns {JSX.Element} The badge element.
 */
function StepBadge({
  number,
  done,
  current,
}: {
  number: number;
  done: boolean;
  current: boolean;
}): JSX.Element {
  if (done) {
    return (
      <span className="flex h-[22px] w-[22px] shrink-0 items-center justify-center rounded-full border border-[#16a34a]/40 bg-[#16a34a]/[0.12]">
        <LuCheck size={12} color="#16a34a" />
      </span>
    );
  }
  if (current) {
    return (
      <span className="flex h-[22px] w-[22px] shrink-0 items-center justify-center rounded-full bg-[#C8175D] font-mono text-[11px] font-semibold text-white shadow-[0_0_0_3px_rgba(200,23,93,0.25)]">
        {number}
      </span>
    );
  }

  return (
    <span className="flex h-[22px] w-[22px] shrink-0 items-center justify-center rounded-full border border-[#e1e3e5] bg-white font-mono text-[11px] text-[#a1a3a5]">
      {number}
    </span>
  );
}

interface FastTrackActionProps {
  unlocked: boolean;
  lockHint: string;
  onRun: () => void;
  busy: boolean;
  icon: React.ReactNode;
  label: string;
}

function FastTrackAction({
  unlocked,
  lockHint,
  onRun,
  busy,
  icon,
  label,
}: FastTrackActionProps) {
  if (!unlocked) {
    return (
      <Link to="/" title={lockHint} className={FAST_TRACK_CLASS}>
        {icon}
        <span className={ACTION_LABEL_CLASS}>{label}</span>
        <LuLock size={12} color="#6d7175" className="shrink-0" />
      </Link>
    );
  }

  return (
    <button
      type="button"
      onClick={onRun}
      disabled={busy}
      title={label}
      className={FAST_TRACK_CLASS}
    >
      {icon}
      <span className={ACTION_LABEL_CLASS}>{label}</span>
    </button>
  );
}

export function SourceMaterialRail({
  domain,
  populatedAt,
  documents,
  uploadPhase,
  onUploadFiles,
  onPasteText,
  pasteSubmittedCount,
  kbBusy,
  exportBusy,
  onExportPdf,
  busyMode,
  onPopulate,
  pushBusy,
  onPushToVisibility,
  enginesReadDone,
  coreComplete,
  coreRemaining,
  pushedOnce,
  onGoToCore,
  canDownloadCheatSheet,
  canExtract,
  cheatSheetBusy,
  onDownloadCheatSheet,
  onOpenExtract,
}: SourceMaterialRailProps) {
  const fileInput = useRef<HTMLInputElement | null>(null);
  const [pasteOpen, setPasteOpen] = useState(false);
  const [pasteTitle, setPasteTitle] = useState('');
  const [pasteBody, setPasteBody] = useState('');
  const [pushPhase, setPushPhase] = useState<'closed' | 'confirm' | 'done'>(
    'closed'
  );
  const [pushResult, setPushResult] = useState<CompanyIdVisibilityPush | null>(
    null
  );

  useEffect(() => {
    if (pasteSubmittedCount > 0) {
      setPasteOpen(false);
      setPasteTitle('');
      setPasteBody('');
    }
  }, [pasteSubmittedCount]);

  const learnedLine = populatedAt
    ? `Learned from ${domain}${
        documents.length
          ? ` and ${documents.length} knowledge document${documents.length === 1 ? '' : 's'}`
          : ''
      }. Last read ${agoLabel(populatedAt)}.`
    : 'Nothing read yet. The first read is queued.';

  const siteReadBusy = busyMode === 'site';
  const engineReadBusy = busyMode === 'web';
  const pasteSaveDisabled = kbBusy || !pasteTitle.trim() || !pasteBody.trim();

  const confirmPush = async () => {
    const result = await onPushToVisibility();
    if (result && result.synced) {
      setPushResult(result);
      setPushPhase('done');
    } else {
      setPushPhase('closed');
    }
  };

  const runSiteRead = () => {
    if (busyMode === null) onPopulate('site');
  };

  const runEngineRead = () => {
    if (busyMode === null) onPopulate('web');
  };

  const openPushConfirm = () => {
    if (!pushBusy) setPushPhase('confirm');
  };

  const closePushModal = () => {
    if (!pushBusy) setPushPhase('closed');
  };

  const openFilePicker = () => {
    if (uploadPhase === 'idle') fileInput.current?.click();
  };

  const handleFilesSelected = (event: React.ChangeEvent<HTMLInputElement>) => {
    if (event.target.files && event.target.files.length > 0) {
      onUploadFiles(event.target.files);
      event.target.value = '';
    }
  };

  const togglePasteOpen = () => setPasteOpen(open => !open);

  const savePastedText = () => {
    if (!pasteSaveDisabled) onPasteText(pasteTitle.trim(), pasteBody.trim());
  };

  // Step gating: block an UNDONE step past the current (first undone) one so
  // a new merchant progresses in order. Done steps stay clickable (rerun)
  // even when a later gap reopens an earlier step; the current step carries
  // the gradient highlight.
  const stepDone = [!!populatedAt, enginesReadDone, coreComplete, pushedOnce];
  const currentStepIndex = stepDone.findIndex(done => !done);
  const stepsDoneCount = stepDone.filter(Boolean).length;
  const allStepsDone = currentStepIndex === -1;

  /**
   * Whether a step is not yet reachable (undone, and not the current one).
   *
   * @param {number} index - Zero-based step index.
   * @returns {boolean} True when the step renders locked.
   */
  const isStepBlocked = (index: number): boolean =>
    !stepDone[index] && index !== currentStepIndex;

  /**
   * Whether a step is the one to take next.
   *
   * @param {number} index - Zero-based step index.
   * @returns {boolean} True on the first undone step.
   */
  const isStepCurrent = (index: number): boolean => index === currentStepIndex;

  /**
   * Connector-line class for the segment between a step and the next one.
   * Green when EITHER end is done, not just the upper one: the four states
   * are independent record facts, so a later step can be done before an
   * earlier one (the push runs automatically on signup), and a grey line
   * feeding a green check read as a broken chain.
   *
   * @param {number} index - Zero-based index of the upper step.
   * @returns {string} The segment class list.
   */
  const connectorClass = (index: number): string =>
    stepDone[index] || stepDone[index + 1] ? 'bg-[#16a34a]/50' : 'bg-[#e1e3e5]';

  // Until both reads are behind them the merchant is still meeting this page,
  // so the current step breathes instead of only carrying a gradient border:
  // on a first visit that is the website read, and the moment it lands the
  // pulse moves to the engines read, which is the one nobody notices.
  const readsPending: boolean = !stepDone[0] || !stepDone[1];
  const stepAttentionClass = (index: number): string =>
    isStepCurrent(index) && readsPending ? 'company-id-step-attention' : '';

  const lockedTitle = 'Finish the previous step first';

  // The four setup steps as data, so the stepper gutter (badge + connector
  // line) renders from one loop and the chain stays visually continuous.
  const steps: {
    key: string;
    onClick: () => void;
    disabled: boolean;
    dimmed: boolean;
    title?: string;
    icon: React.ReactNode;
    label: string;
    /** Optional badge pinned to the right edge of the step button. */
    trailer?: React.ReactNode;
  }[] = [
    {
      key: 'site',
      onClick: runSiteRead,
      disabled: busyMode !== null || isStepBlocked(0),
      dimmed: engineReadBusy,
      title: isStepBlocked(0) ? lockedTitle : undefined,
      icon: (
        <LuRefreshCw
          size={14}
          className={cx(
            'shrink-0',
            siteReadBusy && 'animate-spin [animation-duration:900ms]'
          )}
        />
      ),
      label: siteReadBusy ? 'Reading your site...' : 'What your website says',
    },
    {
      key: 'engines',
      onClick: runEngineRead,
      disabled: busyMode !== null || isStepBlocked(1),
      dimmed: siteReadBusy,
      title: isStepBlocked(1) ? lockedTitle : undefined,
      icon: (
        <LuSparkles
          size={14}
          color={isStepCurrent(1) ? '#ffffff' : '#C8175D'}
          className={cx(
            'shrink-0',
            engineReadBusy && 'animate-spin [animation-duration:1.4s]'
          )}
        />
      ),
      label: engineReadBusy
        ? 'Searching with AI...'
        : 'What Gemini and ChatGPT say',
    },
    {
      key: 'core',
      onClick: onGoToCore,
      disabled: isStepBlocked(2),
      dimmed: false,
      title: isStepBlocked(2)
        ? lockedTitle
        : coreRemaining > 0
          ? 'Jump to the first Core answer still missing'
          : undefined,
      icon: <LuListChecks size={14} className="shrink-0" />,
      label: 'Fill the Core ring at least',
      // The ring counter says "6 of 7" but never which answer is missing, so
      // merchants read the ring as finished and the step as broken. The
      // badge names the gap and the click lands on it.
      trailer:
        coreRemaining > 0 && !isStepBlocked(2) ? (
          <span
            className={cx(
              'ml-auto shrink-0 self-center whitespace-nowrap rounded-full border px-2 py-px font-mono text-[10px]',
              isStepCurrent(2)
                ? 'border-white/50 bg-white/20 text-white'
                : 'border-[#C8175D]/40 bg-[#C8175D]/[0.10] text-[#C8175D]'
            )}
          >
            {coreRemaining} left
          </span>
        ) : null,
    },
    {
      key: 'push',
      onClick: openPushConfirm,
      disabled: pushBusy || isStepBlocked(3),
      dimmed: pushBusy,
      title: isStepBlocked(3)
        ? lockedTitle
        : 'Fill your AI Visibility scan settings from this record',
      icon: (
        <LuEye
          size={14}
          className={cx(
            'shrink-0',
            pushBusy && 'animate-spin [animation-duration:900ms]'
          )}
        />
      ),
      label: pushBusy ? 'Pushing...' : 'Push to AI Visibility',
    },
  ];

  return (
    <div className="flex flex-col gap-3">
      <div className={CARD_CLASS}>
        <div className="p-4 pt-3.5">
          {/* The counter can drop to its own line: at 300px the kicker fills
              the row on its own, and wrapping it would orphan "NICHE". */}
          <div className="flex flex-wrap items-baseline justify-between gap-x-2 gap-y-1">
            <div className={cx(KICKER_CLASS, 'whitespace-nowrap')}>
              Set up your profitable niche
            </div>
            <span
              className={cx(
                'shrink-0 whitespace-nowrap font-mono text-[10px] tracking-[.06em]',
                stepsDoneCount > 0 ? 'text-[#16a34a]' : 'text-[#6d7175]'
              )}
            >
              {stepsDoneCount}/4 DONE
            </span>
          </div>
          <div className="mt-2.5 text-[13px] leading-normal text-[#202223]">
            {allStepsDone ? (
              <>
                All four steps are done - your niche is set up.{' '}
                <span className="font-medium">Rerun any of them</span> whenever
                your site or your story changes.
              </>
            ) : (
              <>
                To set up a profitable niche in AI, fill at least the Core ring
                of your Company ID.{' '}
                <span className="font-medium">
                  Take the four steps from the top
                </span>{' '}
                - each one unlocks the next:
              </>
            )}
          </div>

          <ol className="mt-2 flex list-none flex-col p-0">
            {steps.map((step, index) => (
              <li
                key={step.key}
                aria-current={index === currentStepIndex ? 'step' : undefined}
                className="flex items-stretch gap-2.5"
              >
                {/* Stepper gutter: numbered badge plus the connector line
                    that turns green as steps complete. It sits outside the
                    buttons so locked rows can dim without the sequence
                    itself ever fading. */}
                <div
                  aria-hidden
                  className="flex w-[22px] shrink-0 flex-col items-center"
                >
                  <span
                    className={cx(
                      'w-px flex-1',
                      index === 0 ? 'bg-transparent' : connectorClass(index - 1)
                    )}
                  />
                  <StepBadge
                    number={index + 1}
                    done={stepDone[index]}
                    current={isStepCurrent(index)}
                  />
                  <span
                    className={cx(
                      'w-px flex-1',
                      index === steps.length - 1
                        ? 'bg-transparent'
                        : connectorClass(index)
                    )}
                  />
                </div>
                <button
                  type="button"
                  onClick={step.onClick}
                  disabled={step.disabled}
                  title={step.title}
                  // The badge and connector are decorative, so the state the
                  // sighted merchant reads from them rides on the name.
                  aria-label={`Step ${index + 1} of ${steps.length}${
                    stepDone[index]
                      ? ', done'
                      : isStepBlocked(index)
                        ? ', locked'
                        : ', next up'
                  }: ${step.label}`}
                  className={cx(
                    STEP_BUTTON_CLASS,
                    'my-1 min-w-0 flex-1',
                    isStepCurrent(index) && STEP_BUTTON_CURRENT,
                    stepAttentionClass(index),
                    isStepBlocked(index) && 'opacity-45',
                    step.dimmed && 'opacity-60'
                  )}
                >
                  {step.icon}
                  <span className={ACTION_LABEL_CLASS}>{step.label}</span>
                  {step.trailer}
                  {isStepBlocked(index) && (
                    <LuLock
                      size={12}
                      color="#a1a3a5"
                      className="ml-auto shrink-0 self-center"
                    />
                  )}
                </button>
              </li>
            ))}
          </ol>

          <div className="mt-2 text-[12px] leading-relaxed text-[#4a4d4f]">
            <span className="font-semibold text-[#16a34a]">
              Steps with a green check ran automatically when your account was
              created.
            </span>{' '}
            You can rerun any finished step whenever your site or story changes.
          </div>

          <div className="mt-3.5 text-[13px] leading-relaxed text-[#4a4d4f]">
            Questions? Open and ask Recomaze Copilot.
          </div>
          <div className="mt-2 text-[13px] font-medium leading-relaxed text-[#202223]">
            Want to update everything perfectly or super fast?
          </div>

          <div className="mt-2.5 flex flex-col gap-2">
            <FastTrackAction
              unlocked={canDownloadCheatSheet}
              lockHint="Available on paid plans starting at $39"
              onRun={onDownloadCheatSheet}
              busy={cheatSheetBusy}
              icon={<LuShare2 size={14} className="shrink-0" />}
              label={
                cheatSheetBusy
                  ? 'Preparing...'
                  : 'Download Company ID Cheat Sheet'
              }
            />
            {EXTRACT_FAST_TRACKS.map(({ assistant, icon, label }) => (
              <FastTrackAction
                key={assistant}
                unlocked={canExtract}
                lockHint={EXTRACT_LOCK_HINT}
                onRun={() => onOpenExtract(assistant)}
                busy={false}
                icon={icon}
                label={label}
              />
            ))}
          </div>

          <div className="mt-3 text-[11.5px] leading-normal text-[#6d7175]">
            Proposed values are extracted from your own website and knowledge
            base - what your site doesn&apos;t state stays empty. What Gemini
            and ChatGPT say researches the public web and proposes every field
            it can verify. Push to AI Visibility fills your scan settings
            (niche, tags, country, city, knowledge base) from this record.
            Fields you have edited are never overwritten: new ideas wait for
            your call.
          </div>
        </div>
      </div>

      <div className={CARD_CLASS}>
        <div className="px-4 pt-3.5">
          <div className={KICKER_CLASS}>Source material</div>
          <div className="mt-2.5 text-[13px] leading-normal text-[#4a4d4f]">
            {learnedLine}
          </div>
        </div>

        <div className="flex flex-col gap-0.5 px-4 pb-3.5 pt-3">
          {railDocuments(documents).map(document => (
            <div
              key={document.file_name}
              className="flex items-center gap-2 py-1.5"
            >
              <LuFileText size={13} color="#6d7175" className="shrink-0" />
              <span className="truncate font-mono text-[11.5px] text-[#6d7175]">
                {document.file_name}
              </span>
              <span className="ml-auto shrink-0 font-mono text-[10px] text-[#8c9196]">
                {document.processed_at ? agoLabel(document.processed_at) : ''}
              </span>
            </div>
          ))}

          <input
            ref={fileInput}
            type="file"
            multiple
            accept=".pdf,.doc,.docx,.txt,.md,.csv"
            className="hidden"
            onChange={handleFilesSelected}
          />

          <div className="mt-2.5 flex gap-2">
            <button
              type="button"
              onClick={openFilePicker}
              disabled={uploadPhase !== 'idle'}
              className={cx(
                DASHED_BUTTON_CLASS,
                uploadPhase !== 'idle' && 'cursor-default opacity-70'
              )}
            >
              <LuUpload size={12} />
              {UPLOAD_LABELS[uploadPhase]}
            </button>
            <button
              type="button"
              onClick={togglePasteOpen}
              className={DASHED_BUTTON_CLASS}
            >
              <LuClipboardPaste size={12} />
              Paste text
            </button>
          </div>

          {pasteOpen && (
            <div className="mt-2.5 flex flex-col gap-2">
              <input
                value={pasteTitle}
                onChange={event => setPasteTitle(event.target.value)}
                placeholder="Title, e.g. Shipping FAQ"
                className={RAIL_INPUT_CLASS}
              />
              <textarea
                value={pasteBody}
                onChange={event => setPasteBody(event.target.value)}
                placeholder="Paste the text the record should learn from"
                rows={5}
                className={cx(RAIL_INPUT_CLASS, 'resize-y')}
              />
              <button
                type="button"
                onClick={savePastedText}
                disabled={pasteSaveDisabled}
                className={cx(
                  DASHED_BUTTON_CLASS,
                  'flex-none',
                  pasteSaveDisabled && 'opacity-60'
                )}
              >
                {kbBusy ? 'Saving...' : 'Save to knowledge base'}
              </button>
            </div>
          )}
        </div>

        <div className="border-t border-[#e1e3e5] px-4 py-3">
          <button
            type="button"
            onClick={onExportPdf}
            disabled={exportBusy}
            title="Download the record as a PDF you can send to your agency or partner"
            className={cx(FAST_TRACK_CLASS, exportBusy && 'opacity-70')}
          >
            <LuShare2 size={14} className="shrink-0" />
            {exportBusy ? 'Exporting...' : 'Share your Company ID'}
          </button>
        </div>
      </div>

      {pushPhase !== 'closed' && (
        <div
          role="dialog"
          aria-modal="true"
          onClick={closePushModal}
          className="fixed inset-0 z-[60] flex items-center justify-center bg-black/40 p-4"
        >
          <div
            onClick={event => event.stopPropagation()}
            className="w-full max-w-[440px] rounded-2xl border border-[#e1e3e5] bg-white p-[22px] shadow-[0_24px_60px_rgba(0,0,0,0.18)]"
          >
            {pushPhase === 'confirm' ? (
              <>
                <div className="text-base font-semibold text-[#202223]">
                  Push to AI Visibility
                </div>
                <div className="mt-2 text-[13px] leading-relaxed text-[#6d7175]">
                  This fills your AI Visibility scan settings from your Company
                  ID. These cross over:
                </div>
                <div className="my-3.5 flex flex-col gap-1.5">
                  {[
                    'Niche',
                    'Tags (keywords)',
                    'Country',
                    'City',
                    'Knowledge base',
                  ].map(label => (
                    <div
                      key={label}
                      className="flex items-center gap-2 text-[12.5px] text-[#202223]"
                    >
                      <span className="h-1 w-1 shrink-0 rounded-full bg-[#C8175D]" />
                      {label}
                    </div>
                  ))}
                </div>
                <div className="text-xs leading-relaxed text-[#6d7175]">
                  Matching AI Visibility settings are overwritten with these
                  values. After pushing, review them there and run a Force scan
                  so your next scan uses them.
                </div>
                <div className="mt-[18px] flex justify-end gap-2">
                  <button
                    type="button"
                    onClick={closePushModal}
                    disabled={pushBusy}
                    className={MODAL_GHOST_BUTTON_CLASS}
                  >
                    Cancel
                  </button>
                  <button
                    type="button"
                    onClick={confirmPush}
                    disabled={pushBusy}
                    className={MODAL_PRIMARY_BUTTON_CLASS}
                  >
                    <LuEye
                      size={14}
                      className={
                        pushBusy
                          ? 'animate-spin [animation-duration:900ms]'
                          : ''
                      }
                    />
                    {pushBusy ? 'Pushing...' : 'Push to AI Visibility'}
                  </button>
                </div>
              </>
            ) : (
              <>
                <div className="text-base font-semibold text-[#202223]">
                  Pushed to AI Visibility
                </div>
                <div className="mt-2 text-[13px] leading-relaxed text-[#6d7175]">
                  Your scan settings now carry your Company ID:
                </div>
                <div className="my-3.5 flex flex-col gap-1.5">
                  {[
                    pushResult?.niche ? ['Niche', pushResult.niche] : null,
                    pushResult?.country
                      ? ['Country', pushResult.country]
                      : null,
                    pushResult?.city ? ['City', pushResult.city] : null,
                    pushResult && pushResult.keywords.length > 0
                      ? [
                          'Tags',
                          `${pushResult.keywords.length} keyword${
                            pushResult.keywords.length === 1 ? '' : 's'
                          }`,
                        ]
                      : null,
                  ]
                    .filter((row): row is [string, string] => row !== null)
                    .map(([key, value]) => (
                      <div
                        key={key}
                        className="flex items-center gap-2 text-[12.5px] text-[#202223]"
                      >
                        <span className="min-w-[64px] font-mono text-[10px] font-medium uppercase tracking-[.06em] text-[#6d7175]">
                          {key}
                        </span>
                        {value}
                      </div>
                    ))}
                </div>
                <div className="text-xs leading-relaxed text-[#6d7175]">
                  Review them in AI Visibility and run a Force scan so your next
                  scan uses them.
                </div>
                <div className="mt-[18px] flex justify-end gap-2">
                  <button
                    type="button"
                    onClick={closePushModal}
                    className={MODAL_GHOST_BUTTON_CLASS}
                  >
                    Close
                  </button>
                  <Link
                    to="/ai-visibility"
                    className={cx(MODAL_PRIMARY_BUTTON_CLASS, 'no-underline')}
                  >
                    <LuEye size={14} />
                    Go to AI Visibility
                  </Link>
                </div>
              </>
            )}
          </div>
        </div>
      )}
    </div>
  );
}
