import React, { useEffect, useRef, useState } from 'react';

import type {
  ArticleDetailResponse,
  ArticleStatus,
} from '../../service/visibility/visibility.interface';
import { getArticle } from '../../service/visibility/visibility.service';

import { toneToBadgeClass } from './helpers';

const POLL_INTERVAL_MS = 2_000;
const SLOW_BANNER_AFTER_MS = 90_000;

interface ArticleProgressProps {
  articleId: string;
  clientId: string;
  token: string;
  onReady: (article: ArticleDetailResponse) => void;
  onFailed: (message: string) => void;
}

const stepForStatus = (status: ArticleStatus): 0 | 1 | 2 | 3 => {
  switch (status) {
    case 'pending':
      return 0;
    case 'generating':
      return 1;
    case 'ready':
      return 3;
    case 'failed':
    default:
      return 0;
  }
};

/**
 * Inline progress UI for an article generation job. Polls
 * ``GET /articles/{id}`` every 2s. After 90s without ``ready``, renders
 * a non-blocking "taking longer" banner but keeps polling.
 */
const ArticleProgress = ({
  articleId,
  clientId,
  token,
  onReady,
  onFailed,
}: ArticleProgressProps): JSX.Element => {
  const [status, setStatus] = useState<ArticleStatus>('pending');
  const [slow, setSlow] = useState(false);
  const startedAt = useRef<number>(Date.now());
  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const cancelledRef = useRef(false);
  // Guards against firing onReady/onFailed twice if a poll tick races
  // unmount cleanup. The parent removes this row's pendingId on the
  // first fire, so a duplicate would steal focus from the modal that
  // just opened - looking like the popup briefly appeared and vanished.
  const hasFiredTerminalCallbackRef = useRef(false);

  useEffect(() => {
    cancelledRef.current = false;
    hasFiredTerminalCallbackRef.current = false;
    startedAt.current = Date.now();

    const pollOnce = async () => {
      if (cancelledRef.current || hasFiredTerminalCallbackRef.current) return;
      try {
        const article = await getArticle(clientId, token, articleId);
        if (cancelledRef.current || hasFiredTerminalCallbackRef.current) {
          return;
        }
        const nextStatus = article.summary.status;
        setStatus(nextStatus);

        if (nextStatus === 'ready') {
          hasFiredTerminalCallbackRef.current = true;
          cancelledRef.current = true;
          if (intervalRef.current) clearInterval(intervalRef.current);
          onReady(article);

          return;
        }
        if (nextStatus === 'failed') {
          hasFiredTerminalCallbackRef.current = true;
          cancelledRef.current = true;
          if (intervalRef.current) clearInterval(intervalRef.current);
          onFailed('Content generation failed. Try regenerating.');

          return;
        }

        if (!slow && Date.now() - startedAt.current >= SLOW_BANNER_AFTER_MS) {
          setSlow(true);
        }
      } catch {
        // Transient errors shouldn't kill polling.
      }
    };

    pollOnce();
    intervalRef.current = setInterval(pollOnce, POLL_INTERVAL_MS);

    return () => {
      cancelledRef.current = true;
      if (intervalRef.current) clearInterval(intervalRef.current);
    };
  }, [articleId, clientId, token]);

  const step = stepForStatus(status);

  const Step = ({
    index,
    label,
  }: {
    index: 0 | 1 | 2;
    label: string;
  }): JSX.Element => {
    const active = step === index;
    const done = step > index;
    const tone: 'success' | 'info' | 'attention' = done
      ? 'success'
      : active
        ? 'info'
        : 'attention';

    return (
      <span
        className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium ${toneToBadgeClass(tone)}`}
      >
        {`${index + 1}. ${label}${done ? ' ✓' : active ? '…' : ''}`}
      </span>
    );
  };

  return (
    <div className="flex flex-col gap-2">
      <div className="flex items-center gap-2 flex-wrap">
        <Step index={0} label="Outline" />
        <Step index={1} label="Sections" />
        <Step index={2} label="Finalize" />
      </div>
      <div className="animate-pulse space-y-2">
        <div className="h-3 bg-gray-200 rounded w-11/12" />
        <div className="h-3 bg-gray-200 rounded w-9/12" />
      </div>
      {slow && (
        <div className="rounded-lg border border-blue-200 bg-blue-50 p-3">
          <p className="text-xs text-blue-900">
            This is taking longer than usual. We&apos;ll keep trying - feel free
            to come back later.
          </p>
        </div>
      )}
    </div>
  );
};

export default ArticleProgress;
