import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import { FaWandMagicSparkles } from 'react-icons/fa6';
import { LuFileText } from 'react-icons/lu';

import EmptyState from '../components/agent-analytics/EmptyState';
import ErrorBanner from '../components/agent-analytics/ErrorBanner';
import { Spinner } from '../components/ui/Spinner';
import GenerateIdeasModal from '../components/visibility/GenerateIdeasModal';
import {
  contentTypeLabel,
  PAGE_CONTENT_TYPES,
} from '../components/visibility/helpers';
import PublishedArticlesList from '../components/visibility/PublishedArticlesList';
import RecommendedArticlesList from '../components/visibility/RecommendedArticlesList';
import { useAppStateContext } from '../context/user.data.context';
import type {
  ArticleCounts,
  ArticleSummary,
  PageContentType,
  SuggestionEntry,
} from '../service/visibility/visibility.interface';
import {
  listArticles,
  listBrands,
  listSuggestions,
} from '../service/visibility/visibility.service';

/** How often the list polls while a generation is in flight. */
const POLL_INTERVAL_MS = 4000;

/** Filter value: a specific page type or "all". */
type TypeFilter = PageContentType | 'all';

/** Tabs for the content list. */
const CONTENT_TABS: ReadonlyArray<{
  id: 'recommended' | 'published';
  label: string;
}> = [
  { id: 'recommended', label: 'Recommended' },
  { id: 'published', label: 'Published' },
];

/**
 * Contents page. The dedicated home for generated blog / service / content
 * pages: a page-type filter, Recommended vs Published tabs, and the article
 * cards. "Run template" (and any generation) lands the merchant here.
 *
 * Client-only, like the AI Visibility report - all data lives on the agent
 * backend and is fetched with the merchant's recomaze JWT.
 *
 * @returns {JSX.Element} The Contents page.
 */
const AiVisibilityContents = (): JSX.Element => {
  const { token, clientId } = useAppStateContext();
  const hasClientCreds = Boolean(token && clientId);

  const [brandId, setBrandId] = useState<string>('');
  const [language, setLanguage] = useState<string>('en');
  const [articles, setArticles] = useState<ArticleSummary[]>([]);
  const [suggestions, setSuggestions] = useState<SuggestionEntry[]>([]);
  const [counts, setCounts] = useState<ArticleCounts>({
    recommended: 0,
    published: 0,
  });
  const [typeFilter, setTypeFilter] = useState<TypeFilter>('all');
  const [tab, setTab] = useState<'recommended' | 'published'>('recommended');
  const [ideasOpen, setIdeasOpen] = useState(false);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const hasBrand = brandId.length > 0;

  const loadAll = useCallback(async (): Promise<void> => {
    if (!hasClientCreds) return;
    setLoading(true);
    setError(null);
    try {
      const brandList = await listBrands(clientId as string, token as string);
      const brand = brandList.brands[0] ?? null;
      if (!brand) {
        setBrandId('');
        setLoading(false);

        return;
      }
      setBrandId(brand.brand_id);
      setLanguage(brand.language || 'en');
      const [articleList, suggestionList] = await Promise.all([
        listArticles(clientId as string, token as string, {
          brand_id: brand.brand_id,
        }),
        listSuggestions(clientId as string, token as string, brand.brand_id),
      ]);
      setArticles(articleList.articles);
      setCounts(articleList.counts);
      setSuggestions(suggestionList.suggestions);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to load contents.');
    } finally {
      setLoading(false);
    }
  }, [hasClientCreds, clientId, token]);

  useEffect(() => {
    void loadAll();
  }, [loadAll]);

  const refresh = useCallback(async (): Promise<void> => {
    if (!brandId || !hasClientCreds) return;
    try {
      const [articleList, suggestionList] = await Promise.all([
        // Bypass the 5-min server cache so a finished article stops reporting
        // "generating" on the next poll.
        listArticles(clientId as string, token as string, {
          brand_id: brandId,
          force: true,
        }),
        listSuggestions(clientId as string, token as string, brandId, true),
      ]);
      setArticles(articleList.articles);
      setCounts(articleList.counts);
      setSuggestions(suggestionList.suggestions);
    } catch {
      /* soft-fail: the next poll or navigation picks it up */
    }
  }, [brandId, hasClientCreds, clientId, token]);

  // Poll while anything is still generating so cards advance to "ready" on
  // their own - covers generations kicked off from a template run or elsewhere.
  const refreshRef = useRef(refresh);
  refreshRef.current = refresh;
  useEffect(() => {
    const generating =
      articles.some(
        article =>
          article.status === 'generating' || article.status === 'pending'
      ) ||
      suggestions.some(
        suggestion => suggestion.lifecycle_state === 'generating'
      );
    if (!generating) return;
    const timer = setInterval(() => {
      void refreshRef.current();
    }, POLL_INTERVAL_MS);

    return () => clearInterval(timer);
  }, [articles, suggestions]);

  const sortedArticles = useMemo(
    () =>
      [...articles].sort((first, second) => {
        const firstTime = first.created_at ? Date.parse(first.created_at) : 0;
        const secondTime = second.created_at
          ? Date.parse(second.created_at)
          : 0;

        return secondTime - firstTime;
      }),
    [articles]
  );

  const typeFilteredArticles = useMemo(
    () =>
      typeFilter === 'all'
        ? sortedArticles
        : sortedArticles.filter(
            article => (article.content_type ?? 'blog') === typeFilter
          ),
    [sortedArticles, typeFilter]
  );

  const handleArticleReady = (): void => {
    void refresh();
  };
  const handleArticlePublishedChanged = (): void => {
    void refresh();
  };
  const handleSuggestionRejected = (rejectedId: string): void => {
    setSuggestions(prev =>
      prev.filter(suggestion => suggestion.suggestion_id !== rejectedId)
    );
  };
  const handleArticleDeleted = (deletedId: string): void => {
    setArticles(prev =>
      prev.filter(article => article.article_id !== deletedId)
    );
  };
  const handleIdeasGenerated = (ideas: SuggestionEntry[]): void => {
    setSuggestions(prev => [...ideas, ...prev]);
  };

  if (!hasClientCreds) {
    return (
      <div className="flex items-center justify-center py-24">
        <Spinner className="w-10 h-10 text-gray-700" />
      </div>
    );
  }

  return (
    <div className="mx-auto w-full max-w-[1600px] bg-white p-6 md:p-10">
      <div className="flex flex-col gap-6">
        <header className="flex flex-wrap items-start justify-between gap-3">
          <div className="flex flex-col gap-1">
            <h1 className="flex items-center gap-2 text-xl font-semibold text-gray-900">
              <LuFileText className="h-5 w-5 text-pink-600" aria-hidden />
              Generated content
            </h1>
            <p className="text-sm text-gray-500">
              Every blog, service, and content page you generate lands here. New
              AI-generated drafts appear under Recommended; publish them to move
              them to Published.
            </p>
          </div>
          {hasBrand && (
            <button
              type="button"
              onClick={() => setIdeasOpen(true)}
              className="inline-flex items-center gap-1.5 rounded-md bg-pink-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-pink-700"
            >
              <FaWandMagicSparkles className="h-4 w-4" aria-hidden />
              New content
            </button>
          )}
        </header>

        {error && <ErrorBanner message={error} onRetry={loadAll} />}

        {loading ? (
          <div className="flex items-center justify-center py-24">
            <Spinner className="w-10 h-10 text-gray-700" />
          </div>
        ) : !hasBrand ? (
          <EmptyState message="Set up a brand on the AI Visibility page first, then your contents show up here." />
        ) : (
          <>
            <div className="flex flex-wrap gap-2">
              {(['all', ...PAGE_CONTENT_TYPES] as TypeFilter[]).map(value => (
                <button
                  key={value}
                  type="button"
                  onClick={() => setTypeFilter(value)}
                  className={`rounded-full border px-3 py-1 text-xs font-medium transition-colors ${
                    typeFilter === value
                      ? 'border-pink-600 bg-pink-50 text-pink-700'
                      : 'border-gray-300 bg-white text-gray-500 hover:text-gray-700'
                  }`}
                >
                  {value === 'all' ? 'All types' : contentTypeLabel(value)}
                </button>
              ))}
            </div>

            <div className="flex flex-col gap-3">
              <div
                role="tablist"
                className="flex items-center gap-2 border-b border-gray-200"
              >
                {CONTENT_TABS.map(contentTab => {
                  const isSelected = tab === contentTab.id;
                  const count = counts[contentTab.id];

                  return (
                    <button
                      key={contentTab.id}
                      type="button"
                      role="tab"
                      aria-selected={isSelected}
                      onClick={() => setTab(contentTab.id)}
                      className={`-mb-px border-b-2 px-3 py-2 text-sm font-medium transition-colors ${
                        isSelected
                          ? 'border-pink-600 text-pink-700'
                          : 'border-transparent text-gray-600 hover:text-gray-900'
                      }`}
                    >
                      {contentTab.label} ({count})
                    </button>
                  );
                })}
              </div>

              {tab === 'recommended' && (
                <RecommendedArticlesList
                  suggestions={typeFilter === 'all' ? suggestions : []}
                  articles={typeFilteredArticles}
                  clientId={clientId as string}
                  token={token as string}
                  brandId={brandId}
                  onArticleReady={handleArticleReady}
                  onSuggestionRejected={handleSuggestionRejected}
                  onArticleDeleted={handleArticleDeleted}
                  onArticlePublishedChanged={handleArticlePublishedChanged}
                />
              )}
              {tab === 'published' && (
                <PublishedArticlesList
                  articles={typeFilteredArticles}
                  clientId={clientId as string}
                  token={token as string}
                  onArticlePublishedChanged={handleArticlePublishedChanged}
                />
              )}
            </div>

            <GenerateIdeasModal
              open={ideasOpen}
              onOpenChange={setIdeasOpen}
              clientId={clientId as string}
              token={token as string}
              brandId={brandId}
              language={language}
              onIdeasGenerated={handleIdeasGenerated}
              onArticleStarted={refresh}
            />
          </>
        )}
      </div>
    </div>
  );
};

export default AiVisibilityContents;
