import { useState, useCallback, useMemo } from 'react';
import { FileText, Users, Network, GitFork, Search as SearchIcon, Upload, PlayCircle, RefreshCw, FileType, FileCode, Globe } from 'lucide-react';
import { useQueryClient } from '@tanstack/react-query';
import { Card } from '@/components/ui/Card';
import { Panel } from '@/components/ui/Panel';
import { SearchInput } from '@/components/ui/SearchInput';
import { Badge } from '@/components/ui/Badge';
import { Spinner } from '@/components/ui/Spinner';
import { EmptyState } from '@/components/ui/EmptyState';
import SigmaGraph from '@/components/graph/SigmaGraph';
import type { SigmaGraphNode, SigmaGraphEdge } from '@/components/graph/SigmaGraph';
import { useDocsStats } from '@/hooks/useDocsStats';
import { useDocsSearch } from '@/hooks/useDocsSearch';
import { useDocsCommunities } from '@/hooks/useDocsCommunities';
import { useDocsEntities } from '@/hooks/useDocsEntities';
import { triggerFinalize } from '@/api/docs';

/* ------------------------------------------------------------------ */
/*  Helpers                                                            */
/* ------------------------------------------------------------------ */

const asRecord = (v: unknown): Record<string, unknown> =>
  v && typeof v === 'object' ? (v as Record<string, unknown>) : {};
const num = (v: unknown): number => (typeof v === 'number' ? v : 0);
const str = (v: unknown): string => (typeof v === 'string' ? v : '');
const arr = (v: unknown): unknown[] => (Array.isArray(v) ? v : []);

const ACCENT_BORDERS = [
  'border-l-accent-blue',
  'border-l-accent-green',
  'border-l-accent-amber',
  'border-l-accent-violet',
  'border-l-accent-red',
];

/* ================================================================== */
/*  DocsPage                                                           */
/* ================================================================== */

export default function DocsPage() {
  const queryClient = useQueryClient();

  // ----- search state -----
  const [searchQuery, setSearchQuery] = useState('');
  const [searchMode, setSearchMode] = useState<'local' | 'global'>('local');
  const searchMutation = useDocsSearch();

  const handleSearch = useCallback(
    (q: string) => {
      setSearchQuery(q);
      if (q.trim()) {
        searchMutation.mutate({ query: q, mode: searchMode, topK: 10 });
      }
    },
    [searchMode, searchMutation],
  );

  // ----- finalize state -----
  const [finalizeState, setFinalizeState] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
  const handleFinalize = async () => {
    setFinalizeState('loading');
    try {
      await triggerFinalize();
      setFinalizeState('success');
      setTimeout(() => setFinalizeState('idle'), 2000);
    } catch {
      setFinalizeState('error');
      setTimeout(() => setFinalizeState('idle'), 2000);
    }
  };

  // ----- data hooks -----
  const statsQuery = useDocsStats();
  const communitiesQuery = useDocsCommunities();
  const entitiesQuery = useDocsEntities();

  // ----- derived data -----
  const stats = asRecord(statsQuery.data);

  // Document type breakdown from stats
  const docTypeCounts = useMemo(() => {
    const byType = asRecord(stats['by_type'] ?? stats['doc_types'] ?? stats['type_counts']);
    return {
      markdown: num(byType['markdown'] ?? byType['md']),
      html: num(byType['html']),
      pdf: num(byType['pdf']),
      other: num(byType['other'] ?? byType['text'] ?? byType['docx']),
    };
  }, [stats]);

  const totalDocs = num(stats['document_count'] ?? stats['documents']);

  const communities = useMemo(() => {
    const raw = arr(asRecord(communitiesQuery.data)['communities'] ?? communitiesQuery.data);
    return raw.map((c) => {
      const r = asRecord(c);
      return {
        id: str(r['id'] || r['community_id']),
        title: str(r['title'] || r['name']),
        summary: str(r['summary']),
        terms: arr(r['top_terms'] || r['terms']).map((t) => str(t)),
      };
    });
  }, [communitiesQuery.data]);

  const { graphNodes, graphEdges } = useMemo(() => {
    const raw = asRecord(entitiesQuery.data);
    const rawNodes = arr(raw['nodes'] || raw['entities']);
    const rawEdges = arr(raw['edges'] || raw['relationships']);

    const graphNodes: SigmaGraphNode[] = rawNodes.map((n) => {
      const r = asRecord(n);
      return {
        id: str(r['id'] || r['name']),
        label: String(r['label'] || r['name'] || r['id'] || ''),
        size: num(r['size']) || 5,
        color: str(r['color']) || '#10b981',
      };
    });

    const graphEdges: SigmaGraphEdge[] = rawEdges.map((e) => {
      const r = asRecord(e);
      return {
        source: str(r['source']),
        target: str(r['target']),
        weight: num(r['weight']) || 1,
      };
    });

    return { graphNodes, graphEdges };
  }, [entitiesQuery.data]);

  const searchResults = useMemo(() => {
    if (!searchMutation.data) return [];
    const raw = arr(asRecord(searchMutation.data)['results'] ?? searchMutation.data);
    return raw.map((r) => {
      const rec = asRecord(r);
      return {
        title: str(rec['title'] || rec['name'] || rec['doc_id']),
        snippet: str(rec['snippet'] || rec['summary'] || rec['text']),
        score: num(rec['score'] || rec['relevance']),
        doc_type: str(rec['doc_type']),
      };
    });
  }, [searchMutation.data]);

  const searchActive = searchQuery.trim().length > 0;

  const isRefreshing = statsQuery.isFetching || communitiesQuery.isFetching || entitiesQuery.isFetching;

  const handleRefresh = () => {
    queryClient.invalidateQueries({ queryKey: ['docs'] });
  };

  // ----- finalize button label -----
  const finalizeBtnLabel =
    finalizeState === 'loading'
      ? 'Finalizing…'
      : finalizeState === 'success'
        ? 'Done!'
        : finalizeState === 'error'
          ? 'Failed'
          : 'Finalize';

  return (
    <div className="space-y-6">
      {/* ---- Search Bar Row ---- */}
      <div className="flex items-center gap-3">
        <div className="flex-1">
          <SearchInput
            value={searchQuery}
            onChange={handleSearch}
            placeholder="Search documents…"
            debounceMs={400}
          />
        </div>

        {/* Local / Global toggle */}
        <div className="flex rounded-md border border-border overflow-hidden">
          <button
            className={`px-3 py-2 text-xs font-medium transition-colors ${
              searchMode === 'local'
                ? 'bg-accent-green text-white'
                : 'bg-surface text-text-secondary hover:text-text-primary'
            }`}
            onClick={() => setSearchMode('local')}
          >
            Local
          </button>
          <button
            className={`px-3 py-2 text-xs font-medium transition-colors ${
              searchMode === 'global'
                ? 'bg-accent-green text-white'
                : 'bg-surface text-text-secondary hover:text-text-primary'
            }`}
            onClick={() => setSearchMode('global')}
          >
            Global
          </button>
        </div>

        {/* Upload */}
        <button className="px-3 py-2 text-xs font-medium rounded-md border border-border bg-surface text-text-secondary hover:text-text-primary transition-colors flex items-center gap-1.5">
          <Upload className="w-3.5 h-3.5" />
          Upload
        </button>

        {/* Finalize */}
        <button
          className={`px-3 py-2 text-xs font-medium rounded-md border border-border transition-colors flex items-center gap-1.5 ${
            finalizeState === 'loading'
              ? 'bg-surface text-text-muted cursor-wait'
              : finalizeState === 'success'
                ? 'bg-accent-green text-white'
                : finalizeState === 'error'
                  ? 'bg-accent-red text-white'
                  : 'bg-surface text-text-secondary hover:text-text-primary'
          }`}
          onClick={handleFinalize}
          disabled={finalizeState === 'loading'}
        >
          <PlayCircle className="w-3.5 h-3.5" />
          {finalizeBtnLabel}
        </button>

        {/* Refresh */}
        <button
          onClick={handleRefresh}
          disabled={isRefreshing}
          className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md border border-border bg-surface text-text-secondary hover:text-text-primary hover:border-accent-green transition-colors disabled:opacity-50"
        >
          <RefreshCw className={`w-3.5 h-3.5 ${isRefreshing ? 'animate-spin' : ''}`} />
          Refresh
        </button>
      </div>

      {/* ---- Search Results Panel ---- */}
      {searchActive && (
        <Panel title="Search Results">
          {searchMutation.isPending ? (
            <div className="flex justify-center py-8">
              <Spinner size="md" />
            </div>
          ) : searchResults.length === 0 ? (
            <EmptyState icon={SearchIcon} title="No results found" description="Try a different query or search mode." />
          ) : (
            <div className="space-y-2 max-h-80 overflow-y-auto">
              {searchResults.map((r, i) => (
                <div
                  key={i}
                  className="p-3 rounded-md border border-border bg-surface hover:bg-surface-hover cursor-pointer transition-colors"
                >
                  <div className="flex items-center justify-between mb-1">
                    <span className="text-sm font-medium text-text-primary">{r.title || 'Untitled'}</span>
                    <div className="flex items-center gap-2">
                      {r.doc_type && <Badge status="info">{r.doc_type}</Badge>}
                      <span className="text-xs text-text-muted">{(r.score * 100).toFixed(0)}%</span>
                    </div>
                  </div>
                  {r.snippet && (
                    <p className="text-xs text-text-secondary line-clamp-2">{r.snippet}</p>
                  )}
                </div>
              ))}
            </div>
          )}
        </Panel>
      )}

      {/* ---- Stats Row ---- */}
      <div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
        <Card
          title="Documents"
          value={totalDocs}
          icon={FileText}
          gradient="green"
        />
        <Card
          title="Communities"
          value={num(stats['community_count'] ?? stats['communities'])}
          icon={Users}
          gradient="green"
        />
        <Card
          title="Entities"
          value={num(stats['entity_count'] ?? stats['entities'])}
          icon={Network}
          gradient="violet"
        />
        <Card
          title="Relationships"
          value={num(stats['relationship_count'] ?? stats['relationships'])}
          icon={GitFork}
          gradient="amber"
        />
      </div>

      {/* ---- Document Type Breakdown ---- */}
      <div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
        <Card title="Markdown" value={docTypeCounts.markdown} icon={FileCode} gradient="blue" subtitle="documents" />
        <Card title="HTML" value={docTypeCounts.html} icon={Globe} gradient="amber" subtitle="documents" />
        <Card title="PDF" value={docTypeCounts.pdf} icon={FileType} gradient="red" subtitle="documents" />
        <Card title="Other" value={docTypeCounts.other} icon={FileText} gradient="none" subtitle="documents" />
      </div>

      {/* ---- Row 2: Graph + Communities ---- */}
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
        {/* Entity Graph */}
        <Panel title="Entity Graph">
          {entitiesQuery.isLoading ? (
            <div className="flex justify-center py-12">
              <Spinner size="lg" />
            </div>
          ) : graphNodes.length === 0 ? (
            <EmptyState icon={Network} title="No entities" description="Upload and finalize documents to populate the graph." />
          ) : (
            <SigmaGraph nodes={graphNodes} edges={graphEdges} height="360px" />
          )}
        </Panel>

        {/* Communities */}
        <Panel title="Communities">
          {communitiesQuery.isLoading ? (
            <div className="flex justify-center py-12">
              <Spinner size="lg" />
            </div>
          ) : communities.length === 0 ? (
            <EmptyState icon={Users} title="No communities" description="Communities appear after finalization." />
          ) : (
            <div className="space-y-3 max-h-[360px] overflow-y-auto">
              {communities.map((c, i) => (
                <div
                  key={c.id || i}
                  className={`border-l-4 ${ACCENT_BORDERS[i % ACCENT_BORDERS.length]} rounded-md border border-border bg-surface p-3`}
                >
                  <p className="text-sm font-medium text-text-primary mb-1">{c.title || `Community ${i + 1}`}</p>
                  {c.summary && (
                    <p className="text-xs text-text-secondary mb-2 line-clamp-2">{c.summary}</p>
                  )}
                  {c.terms.length > 0 && (
                    <div className="flex flex-wrap gap-1">
                      {c.terms.slice(0, 8).map((t, ti) => (
                        <span
                          key={ti}
                          className="px-1.5 py-0.5 text-[10px] bg-surface-elevated text-text-secondary rounded"
                        >
                          {t}
                        </span>
                      ))}
                    </div>
                  )}
                </div>
              ))}
            </div>
          )}
        </Panel>
      </div>
    </div>
  );
}
