import React, { useEffect, useState } from 'react';
import { FiEdit3, FiFilter } from 'react-icons/fi';

import InfoTooltip from '../agent-analytics/InfoTooltip';
import type {
  ContentGap,
  FunnelCoverageResponse,
  FunnelStageCoverage,
  FunnelStageStatus,
} from '../../service/visibility/visibility.interface';
import {
  generateArticle,
  getFunnelCoverage,
} from '../../service/visibility/visibility.service';

import ArticleModal from './ArticleModal';
import ArticleProgress from './ArticleProgress';
import GenerateLanguagesDialog from './GenerateLanguagesDialog';
import { toneToBadgeClass } from './helpers';

interface FunnelCoveragePanelProps {
  clientId: string;
  token: string;
  brandId: string;
  language?: string | null;
  /** Fired when a gap's generated article finishes, so the parent can refresh. */
  onArticleGenerated?: () => void;
}

const STAGE_COPY: Record<string, { label: string; hint: string }> = {
  research: {
    label: 'Research',
    hint: 'Top of funnel: what-is, best-for, use-case questions.',
  },
  comparison: {
    label: 'Comparison',
    hint: 'Mid funnel: alternatives, X vs Y, weighing options.',
  },
  evaluation: {
    label: 'Evaluation',
    hint: 'Bottom funnel: reviews, worth-it, reliability.',
  },
};

const STATUS_TONE: Record<
  FunnelStageStatus,
  'success' | 'warning' | 'critical' | undefined
> = {
  strong: 'success',
  weak: 'warning',
  absent: 'critical',
  untracked: undefined,
};

const STATUS_LABEL: Record<FunnelStageStatus, string> = {
  strong: 'Strong',
  weak: 'Weak',
  absent: 'Absent',
  untracked: 'Collecting',
};

const STATUS_TEXT: Record<FunnelStageStatus, string> = {
  strong: 'text-green-600',
  weak: 'text-yellow-600',
  absent: 'text-red-600',
  untracked: 'text-gray-400',
};

const STATUS_BAR: Record<FunnelStageStatus, string> = {
  strong: 'bg-green-500',
  weak: 'bg-yellow-500',
  absent: 'bg-red-500',
  untracked: 'bg-gray-300',
};

/** One funnel stage as a compact tile: status, coverage %, and a progress bar. */
function StageTile({ stage }: { stage: FunnelStageCoverage }): JSX.Element {
  const copy = STAGE_COPY[stage.stage] ?? { label: stage.stage, hint: '' };
  const status = stage.status;
  const tracked = status !== 'untracked';

  return (
    <div className="flex flex-col gap-2 rounded-xl border border-gray-200 bg-gray-50 p-3">
      <div className="flex items-center justify-between gap-2">
        <span className="text-sm font-semibold text-gray-900">
          {copy.label}
        </span>
        <span
          className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${toneToBadgeClass(STATUS_TONE[status])}`}
        >
          {STATUS_LABEL[status]}
        </span>
      </div>
      <div className="flex items-baseline gap-1.5">
        <span className={`text-2xl font-bold ${STATUS_TEXT[status]}`}>
          {tracked ? `${Math.round(stage.coverage_pct)}%` : '—'}
        </span>
        <span className="text-[11px] text-gray-500">
          {stage.prompts_present}/{stage.prompts_total} prompts
        </span>
      </div>
      <div className="h-1.5 w-full overflow-hidden rounded-full bg-gray-200">
        <div
          className={`h-full rounded-full ${STATUS_BAR[status]}`}
          style={{ width: `${tracked ? stage.coverage_pct : 0}%` }}
        />
      </div>
      <p className="text-[11px] leading-snug text-gray-500">{copy.hint}</p>
    </div>
  );
}

/**
 * Funnel-coverage panel (Beta): where AI engines surface the brand across the
 * buyer journey (Research → Comparison → Evaluation) plus the content gaps to
 * write. Fetches client-side; clicking a gap dispatches article generation.
 */
const FunnelCoveragePanel = ({
  clientId,
  token,
  brandId,
  language,
  onArticleGenerated,
}: FunnelCoveragePanelProps): JSX.Element | null => {
  const [data, setData] = useState<FunnelCoverageResponse | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  // Gap generation, mirroring the TopWinsLosses flow. All keyed by gap prompt.
  const [langDialogGap, setLangDialogGap] = useState<ContentGap | null>(null);
  const [pendingByGap, setPendingByGap] = useState<Record<string, string>>({});
  const [errorByGap, setErrorByGap] = useState<Record<string, string>>({});
  const [busyByGap, setBusyByGap] = useState<Record<string, boolean>>({});
  const [dismissedGaps, setDismissedGaps] = useState<Set<string>>(
    () => new Set()
  );
  const [openArticleId, setOpenArticleId] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    setError(null);
    getFunnelCoverage(clientId, token, brandId)
      .then(result => {
        if (!cancelled) setData(result);
      })
      .catch(err => {
        if (!cancelled)
          setError(
            err instanceof Error
              ? err.message
              : 'Failed to load funnel coverage.'
          );
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });

    return () => {
      cancelled = true;
    };
  }, [clientId, token, brandId]);

  const handleGenerate = async (gap: ContentGap, languages: string[]) => {
    setLangDialogGap(null);
    setBusyByGap(prev => ({ ...prev, [gap.prompt]: true }));
    setErrorByGap(prev => {
      const next = { ...prev };
      delete next[gap.prompt];

      return next;
    });
    try {
      const dispatch = await generateArticle(clientId, token, {
        brand_id: brandId,
        topic: gap.prompt,
        target_prompts: [gap.prompt],
        language: language ?? undefined,
        languages: languages.length ? languages : undefined,
        triggered_by: 'manual',
      });
      setPendingByGap(prev => ({ ...prev, [gap.prompt]: dispatch.article_id }));
    } catch (err) {
      setErrorByGap(prev => ({
        ...prev,
        [gap.prompt]:
          err instanceof Error ? err.message : 'Failed to start generation.',
      }));
    } finally {
      setBusyByGap(prev => ({ ...prev, [gap.prompt]: false }));
    }
  };

  // Nothing scanned yet: stay silent rather than render an empty card.
  if (!loading && !error && (!data || data.stages.length === 0)) {
    return null;
  }

  const gaps = (data?.content_gaps ?? []).filter(
    gap => !dismissedGaps.has(gap.prompt)
  );

  return (
    <>
      <div className="flex flex-col gap-4 rounded-xl border border-gray-200 bg-white p-5">
        <div className="flex flex-col gap-1">
          <div className="flex items-center gap-2">
            <FiFilter className="h-4 w-4 text-yellow-600" />
            <h3 className="text-base font-semibold text-gray-900">
              Funnel coverage
            </h3>
            <span
              className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${toneToBadgeClass('attention')}`}
            >
              Beta
            </span>
            <InfoTooltip text="Groups your tracked prompts into Research, Comparison, and Evaluation stages and shows how often AI answers mention you at each one. Gaps lower in the funnel are the highest-intent content to write next." />
          </div>
          <p className="text-xs text-gray-500">
            Where AI engines surface your brand across the buyer journey. A weak
            or absent stage is a content gap you can close.
          </p>
        </div>

        {loading && (
          <div className="animate-pulse space-y-2">
            <div className="h-4 w-1/2 rounded bg-gray-200" />
            <div className="h-4 w-2/3 rounded bg-gray-200" />
            <div className="h-4 w-1/3 rounded bg-gray-200" />
          </div>
        )}

        {error && <p className="text-sm text-red-700">{error}</p>}

        {!loading && !error && data && (
          <>
            <div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
              {data.stages.map(stage => (
                <StageTile key={stage.stage} stage={stage} />
              ))}
            </div>

            {gaps.length > 0 && (
              <div className="flex flex-col gap-2 border-t border-gray-200 pt-3">
                <div>
                  <p className="text-sm font-semibold text-yellow-700">
                    Content gaps to write{' '}
                    <span className="text-gray-500">({gaps.length})</span>
                  </p>
                  <p className="text-[11px] text-gray-500">
                    Click a gap to generate an article that targets that prompt.
                  </p>
                </div>

                <div className="flex flex-col gap-1.5">
                  {gaps.map(gap => {
                    const pendingId = pendingByGap[gap.prompt];
                    const isGenerating = Boolean(pendingId);
                    const err = errorByGap[gap.prompt];
                    const busy = busyByGap[gap.prompt];

                    return (
                      <div key={gap.prompt}>
                        <button
                          type="button"
                          disabled={isGenerating || busy}
                          title="Generate an article that targets this prompt"
                          onClick={() => setLangDialogGap(gap)}
                          className="flex w-full items-center justify-between gap-2 rounded-lg border border-yellow-200 bg-yellow-50 px-3 py-2 text-left transition-colors hover:border-yellow-300 hover:bg-yellow-100 disabled:cursor-default disabled:opacity-70"
                        >
                          <span className="flex min-w-0 items-center gap-2">
                            <FiEdit3 className="h-3.5 w-3.5 flex-shrink-0 text-yellow-600" />
                            <span className="truncate text-sm text-gray-900">
                              {gap.prompt}
                            </span>
                          </span>
                          <span className="flex flex-shrink-0 items-center gap-2">
                            {isGenerating ? (
                              <span className="text-[11px] text-gray-500">
                                Generating…
                              </span>
                            ) : (
                              gap.demand > 0 && (
                                <span
                                  className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${toneToBadgeClass('warning')}`}
                                >
                                  {`${gap.demand}× in chat`}
                                </span>
                              )
                            )}
                            <span className="text-[11px] capitalize text-gray-500">
                              {gap.stage}
                            </span>
                          </span>
                        </button>

                        {err && (
                          <p className="pt-1 text-xs text-red-700">{err}</p>
                        )}

                        {isGenerating && pendingId && (
                          <div className="pt-1.5">
                            <ArticleProgress
                              articleId={pendingId}
                              clientId={clientId}
                              token={token}
                              onReady={article => {
                                setPendingByGap(prev => {
                                  const next = { ...prev };
                                  delete next[gap.prompt];

                                  return next;
                                });
                                setDismissedGaps(prev => {
                                  const next = new Set(prev);
                                  next.add(gap.prompt);

                                  return next;
                                });
                                setOpenArticleId(article.summary.article_id);
                                onArticleGenerated?.();
                              }}
                              onFailed={message =>
                                setErrorByGap(prev => ({
                                  ...prev,
                                  [gap.prompt]: message,
                                }))
                              }
                            />
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
              </div>
            )}
          </>
        )}
      </div>

      <ArticleModal
        open={openArticleId !== null}
        articleId={openArticleId}
        onClose={() => setOpenArticleId(null)}
        clientId={clientId}
        token={token}
      />

      <GenerateLanguagesDialog
        open={langDialogGap !== null}
        onOpenChange={next => {
          if (!next) setLangDialogGap(null);
        }}
        primaryLanguage={language || 'en'}
        busy={langDialogGap ? Boolean(busyByGap[langDialogGap.prompt]) : false}
        onConfirm={languages => {
          if (langDialogGap) void handleGenerate(langDialogGap, languages);
        }}
      />
    </>
  );
};

export default FunnelCoveragePanel;
