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

import { CardSkeleton } from '../agent-analytics/CardSkeleton';
import EmptyState from '../agent-analytics/EmptyState';
import InfoTooltip from '../agent-analytics/InfoTooltip';
import type {
  PromptCategory,
  PromptMetricTrend,
  PromptResponse,
} from '../../service/visibility/visibility.interface';
import {
  getPromptMetrics,
  listPrompts,
} from '../../service/visibility/visibility.service';

import { toneToBadgeClass } from './helpers';
import EditPromptModal from './EditPromptModal';
import PromptResponseModal from './PromptResponseModal';
import { PromptTrendChip } from './PromptTrend';
import RegeneratePromptsModal from './RegeneratePromptsModal';

interface TrackedPromptsListProps {
  clientId: string;
  token: string;
  brandId: string;
  brandDomain: string | null;
}

const CATEGORY_META: Record<
  PromptCategory,
  { label: string; color: string; description: string }
> = {
  product: {
    label: 'Product',
    color: '#2c6ecb',
    description:
      "Direct product-comparison prompts - 'best …', 'where can I buy …', 'which …'.",
  },
  scenario: {
    label: 'Scenario',
    color: '#8a3ffc',
    description:
      "Situational prompts - 'I need … for …', 'what do I buy for a wedding'.",
  },
  best_of: {
    label: 'Best of',
    color: '#3f7b00',
    description:
      "Listicle-style prompts - 'top N brands for …', 'best companies that …'.",
  },
  geo: {
    label: 'Geo',
    color: '#e57200',
    description:
      'Location-grounded prompts - city/country/market hints in the query.',
  },
};

const CATEGORY_ORDER: PromptCategory[] = [
  'product',
  'scenario',
  'best_of',
  'geo',
];

/**
 * Section showing the 16 monitored prompts grouped by category. Clicking a
 * prompt opens {@link PromptResponseModal} with per-engine evidence.
 */
const TrackedPromptsList = ({
  clientId,
  token,
  brandId,
  brandDomain,
}: TrackedPromptsListProps): JSX.Element => {
  const [prompts, setPrompts] = useState<PromptResponse[]>([]);
  const [metricsByPrompt, setMetricsByPrompt] = useState<
    Record<string, PromptMetricTrend>
  >({});
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [selectedPromptId, setSelectedPromptId] = useState<string | null>(null);
  const [editingPromptId, setEditingPromptId] = useState<string | null>(null);
  const [regenerateOpen, setRegenerateOpen] = useState(false);

  const refreshPrompts = (): void => {
    listPrompts(clientId, token, brandId)
      .then(res => {
        setPrompts(res.prompts || []);
      })
      .catch(() => {
        // Silent: optimistic merge below keeps the list usable.
      });
  };

  const handlePromptSaved = (updated: PromptResponse): void => {
    setPrompts(prev => {
      const matched = prev.some(
        existing => existing.prompt_id === updated.prompt_id
      );
      if (!matched) {
        return [...prev, updated];
      }
      return prev.map(existing =>
        existing.prompt_id === updated.prompt_id ? updated : existing
      );
    });
    refreshPrompts();
  };

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    setError(null);
    listPrompts(clientId, token, brandId)
      .then(res => {
        if (cancelled) return;
        setPrompts(res.prompts || []);
      })
      .catch(err => {
        if (cancelled) return;
        setError(
          err instanceof Error ? err.message : 'Failed to load prompts.'
        );
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });

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

  useEffect(() => {
    // Trends load independently of the prompt list so a missing/empty rollup
    // (pre-deploy, or before the first scan) never blocks the prompts grid.
    let cancelled = false;
    getPromptMetrics(clientId, token, brandId)
      .then(res => {
        if (cancelled) return;
        const next: Record<string, PromptMetricTrend> = {};
        for (const trend of res.prompts || []) {
          next[trend.prompt_id] = trend;
        }
        setMetricsByPrompt(next);
      })
      .catch(() => {
        // Silent: the cards just render without a trend chip.
      });

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

  const grouped = useMemo(() => {
    const buckets: Record<PromptCategory, PromptResponse[]> = {
      product: [],
      scenario: [],
      best_of: [],
      geo: [],
    };
    for (const p of prompts) {
      if (!p.enabled) continue;
      if (p.category in buckets) {
        buckets[p.category as PromptCategory].push(p);
      }
    }

    return buckets;
  }, [prompts]);

  const enabledCount = useMemo(
    () => prompts.filter(p => p.enabled).length,
    [prompts]
  );

  const selectedPrompt =
    selectedPromptId != null
      ? (prompts.find(row => row.prompt_id === selectedPromptId) ?? null)
      : null;

  const editingPrompt =
    editingPromptId != null
      ? (prompts.find(row => row.prompt_id === editingPromptId) ?? null)
      : null;

  return (
    <>
      <div className="flex flex-col gap-3">
        <div className="flex items-center gap-2">
          <h2 className="text-xl font-semibold text-gray-900">
            {`Tracked prompts${enabledCount ? ` (${enabledCount})` : ''}`}
          </h2>
          <InfoTooltip text="The 16 prompts our scanner sends to AI engines each week to measure your visibility. The trend chip on each card shows that prompt's visibility score and recent direction. Click a prompt to see how the AI actually answered it." />
        </div>

        <p className="text-xs text-gray-500">
          Each card shows that prompt&apos;s AI-visibility score (
          <span className="font-medium text-gray-900">0-100</span>, how strongly
          AI engines surface you for it) and its change since tracking started.
          Higher and rising is better.
        </p>

        <div className="flex items-center justify-between gap-2">
          <p className="text-sm text-gray-500">
            Not matching what you sell? Rebuild them from your live catalog.
          </p>
          <button
            type="button"
            onClick={() => setRegenerateOpen(true)}
            className="shrink-0 rounded-md bg-pink-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-pink-700"
          >
            Regenerate prompts
          </button>
        </div>

        {error && (
          <div className="rounded-xl border border-red-200 bg-red-50 p-3">
            <p className="text-xs text-red-700">{error}</p>
          </div>
        )}

        {loading ? (
          <div
            style={{
              display: 'grid',
              gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',
              gap: 16,
            }}
          >
            <CardSkeleton />
            <CardSkeleton />
            <CardSkeleton />
            <CardSkeleton />
          </div>
        ) : enabledCount === 0 ? (
          <EmptyState message="No prompts tracked yet. Run a scan or adopt chat themes below to populate this list." />
        ) : (
          <div
            style={{
              display: 'grid',
              gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))',
              gap: 16,
              alignItems: 'start',
            }}
          >
            {CATEGORY_ORDER.map(cat => {
              const items = grouped[cat];
              const meta = CATEGORY_META[cat];
              if (items.length === 0) return null;

              return (
                <div className="flex flex-col gap-2" key={cat}>
                  <div className="flex items-center gap-2">
                    <span
                      aria-hidden="true"
                      className="inline-block w-2.5 h-2.5 rounded-full"
                      style={{ background: meta.color }}
                    />
                    <span className="text-sm font-semibold text-gray-900">
                      {meta.label}
                    </span>
                    <InfoTooltip text={meta.description} />
                  </div>

                  <div className="flex flex-col gap-1.5">
                    {items.map(prompt => (
                      <div
                        key={prompt.prompt_id}
                        className="group relative rounded-xl bg-gray-50 border border-gray-200 hover:bg-gray-100 transition-colors"
                      >
                        <button
                          type="button"
                          onClick={() => setSelectedPromptId(prompt.prompt_id)}
                          className="block w-full text-left rounded-xl cursor-pointer p-3 pr-10"
                        >
                          <div className="flex flex-col gap-1">
                            <div className="flex items-center gap-1.5 flex-wrap">
                              <span
                                className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium ${toneToBadgeClass('info')}`}
                              >
                                {meta.label}
                              </span>
                              {prompt.source && prompt.source !== 'auto' && (
                                <span
                                  className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium ${toneToBadgeClass(undefined)}`}
                                >
                                  {prompt.source}
                                </span>
                              )}
                            </div>
                            <p className="text-sm text-gray-900">
                              {prompt.prompt_text}
                            </p>
                            {metricsByPrompt[prompt.prompt_id] && (
                              <div className="pt-1">
                                <PromptTrendChip
                                  currentScore={
                                    metricsByPrompt[prompt.prompt_id]
                                      .current_score
                                  }
                                  deltaScore={
                                    metricsByPrompt[prompt.prompt_id]
                                      .delta_score
                                  }
                                  status={
                                    metricsByPrompt[prompt.prompt_id].status
                                  }
                                  series={
                                    metricsByPrompt[prompt.prompt_id].series
                                  }
                                />
                              </div>
                            )}
                          </div>
                        </button>
                        <button
                          type="button"
                          onClick={event => {
                            event.stopPropagation();
                            setEditingPromptId(prompt.prompt_id);
                          }}
                          aria-label={`Edit prompt: ${prompt.prompt_text}`}
                          className="absolute right-2 top-2 cursor-pointer rounded-md p-1.5 text-gray-400 transition-colors hover:bg-white hover:text-gray-700"
                        >
                          <svg
                            xmlns="http://www.w3.org/2000/svg"
                            width="14"
                            height="14"
                            viewBox="0 0 24 24"
                            fill="none"
                            stroke="currentColor"
                            strokeWidth="2"
                            strokeLinecap="round"
                            strokeLinejoin="round"
                            aria-hidden="true"
                          >
                            <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
                            <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
                          </svg>
                        </button>
                      </div>
                    ))}
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </div>

      <PromptResponseModal
        open={selectedPrompt !== null}
        prompt={selectedPrompt}
        trend={
          selectedPromptId ? (metricsByPrompt[selectedPromptId] ?? null) : null
        }
        onClose={() => setSelectedPromptId(null)}
        clientId={clientId}
        token={token}
        brandId={brandId}
        brandDomain={brandDomain}
      />

      <EditPromptModal
        open={editingPrompt !== null}
        prompt={editingPrompt}
        onClose={() => setEditingPromptId(null)}
        onSaved={handlePromptSaved}
        clientId={clientId}
        token={token}
        brandId={brandId}
      />

      <RegeneratePromptsModal
        open={regenerateOpen}
        onClose={() => setRegenerateOpen(false)}
        onRegenerated={next => setPrompts(next)}
        clientId={clientId}
        token={token}
        brandId={brandId}
      />
    </>
  );
};

export default TrackedPromptsList;
