'use client';

import { useState, useEffect, useCallback } from 'react';
import PortalLayout from '@/app/layout-portal';
import { explorerLs, explorerCat, type IPFSEntry } from '@/lib/api/explorer';
import { listPins } from '@/lib/api/pins';
import CIDInput from './components/CIDInput';
import DirectoryListing from './components/DirectoryListing';
import FilePreview from './components/FilePreview';
import Breadcrumbs from './components/Breadcrumbs';
import PinBadge from './components/PinBadge';
import GatewayLink from './components/GatewayLink';
import SearchBar from '@/components/search';
import type { SearchResult } from '@/lib/search-index';
import { isTextFile, extractText, addToIndex, clearIndex, getIndexStats } from '@/lib/search-index';
import { Search, AlertCircle, RefreshCw, Database, Loader2 } from 'lucide-react';
import Skeleton from '@/components/Skeleton';

import ErrorBoundary from '@/components/ErrorBoundary';

import { loadRecentCids, saveRecentCid, findFilename, type ExplorerState, type BreadcrumbSegment } from './helpers';

export default function ExplorerPage() {
  const [cid, setCid] = useState('');
  const [entries, setEntries] = useState<IPFSEntry[]>([]);
  const [previewCid, setPreviewCid] = useState<string | null>(null);
  const [previewContent, setPreviewContent] = useState<string | null>(null);
  const [previewLoading, setPreviewLoading] = useState(false);
  const [path, setPath] = useState<BreadcrumbSegment[]>([]);
  const [state, setState] = useState<ExplorerState>('idle');
  const [error, setError] = useState('');
  const [pins, setPins] = useState<string[]>([]);
  const [recentCids] = useState<string[]>(loadRecentCids);
  const [indexStats, setIndexStats] = useState(getIndexStats);
  const [rebuilding, setRebuilding] = useState(false);

  // Load pins from the pins page (shared localStorage or just track in-memory)
  function handlePinToggle(cid: string) {
    setPins((prev) => (prev.includes(cid) ? prev : [...prev, cid]));
  }

  async function navigateTo(targetCid: string) {
    setCid(targetCid);
    setPreviewCid(null);
    setPreviewContent(null);
    setError('');
    setState('loading');
    saveRecentCid(targetCid);

    // Simple IPNS detection — if it contains a dot, assume it's an IPNS name
    if (targetCid.includes('.') && !targetCid.startsWith('Qm') && !targetCid.startsWith('baf')) {
      setState('resolving');
    }

    try {
      const result = await explorerLs(targetCid);
      setEntries(result);
      setState('loaded');
    } catch (e) {
      const message = e instanceof Error ? e.message : 'Failed to browse CID';
      setError(message);
      setState('error');
      setEntries([]);
    }
  }

  async function handleNavigate(hash: string, name: string) {
    setPath((prev) => [...prev, { cid: hash, name }]);
    await navigateTo(hash);
  }

  async function handleBreadcrumbNavigate(cid: string) {
    // Find the index of the clicked segment
    const idx = path.findIndex((s) => s.cid === cid);
    if (idx >= 0) {
      setPath(path.slice(0, idx));
    } else {
      setPath([]);
    }
    await navigateTo(cid);
  }

  async function handlePreview(hash: string) {
    setPreviewCid(hash);
    setPreviewLoading(true);
    setPreviewContent(null);
    try {
      const content = await explorerCat(hash);
      setPreviewContent(content);
    } catch (err) {
      console.error('[ExplorerPage] Failed to fetch preview content:', err);
      setPreviewContent(null);
    } finally {
      setPreviewLoading(false);
    }
  }

  function handleClosePreview() {
    setPreviewCid(null);
    setPreviewContent(null);
  }

  function handleRetry() {
    if (cid) navigateTo(cid);
  }

  /* ── Search ── */

  function handleSearchResult(result: SearchResult) {
    navigateTo(result.entry.cid);
  }

  async function rebuildSearchIndex() {
    setRebuilding(true);
    try {
      const pinsList = await listPins();
      clearIndex();
      let indexed = 0;
      let failed = 0;
      for (const pin of pinsList) {
        if (isTextFile(pin.name) || !pin.name) {
          try {
            const text = await explorerCat(pin.cid);
            const extracted = extractText(text);
            if (extracted.length > 0) {
              addToIndex({
                cid: pin.cid,
                name: pin.name || pin.cid.slice(0, 20),
                type: 'file',
                text: extracted,
                size: text.length,
                indexedAt: Date.now(),
              });
              indexed++;
            }
          } catch (err) {
            console.error('[ExplorerPage] Failed to index pin:', err);
            failed++;
          }
        }
      }
      setIndexStats({ entries: indexed, totalChars: 0, lastIndexed: Date.now() });
    } finally {
      setRebuilding(false);
    }
  }

  const isPinned = previewCid ? pins.includes(previewCid) : false;

  return (
    <PortalLayout>
      <ErrorBoundary label="Verkenner">
      {/* Page header */}
      <div className="mb-6">
        <h1 className="text-2xl font-bold text-white">IPFS Explorer</h1>
        <p className="text-sm text-surface-400 mt-1">
          Browse IPFS content by CID — directories, files, and pin management
        </p>
      </div>

      {/* Search + Index rebuild */}
      <div className="mb-4 flex items-start gap-3">
        <div className="flex-1">
          <SearchBar onSelect={handleSearchResult} placeholder="Search indexed files…" />
        </div>
        <button
          onClick={rebuildSearchIndex}
          disabled={rebuilding}
          className="flex items-center gap-1.5 px-3 py-2.5 rounded-xl bg-surface-900 border border-surface-700 text-xs text-surface-400 hover:text-surface-200 hover:border-surface-600 transition-colors disabled:opacity-50 shrink-0"
          title={`${indexStats.entries} entries indexed`}
        >
          {rebuilding ? (
            <Loader2 className="w-3.5 h-3.5 animate-spin" />
          ) : (
            <Database className="w-3.5 h-3.5" />
          )}
          <span className="hidden sm:inline">Index</span>
        </button>
      </div>

      {/* CID input */}
      <div className="mb-6">
        <CIDInput onNavigate={navigateTo} />
      </div>

      {/* Recent CIDs suggestion */}
      {state === 'idle' && recentCids.length > 0 && (
        <div className="mb-6 animate-fade-in">
          <p className="text-xs text-surface-500 mb-2">Recent CIDs</p>
          <div className="flex flex-wrap gap-2">
            {recentCids.slice(0, 5).map((rc) => (
              <button
                key={rc}
                onClick={() => navigateTo(rc)}
                className="px-3 py-1.5 rounded-lg bg-surface-800 text-xs font-mono text-surface-400 hover:text-surface-200 hover:bg-surface-700 transition-colors"
              >
                {rc.slice(0, 12)}…
              </button>
            ))}
          </div>
        </div>
      )}

      {/* Idle state */}
      {state === 'idle' && (
        <div className="glass rounded-xl p-12 flex flex-col items-center justify-center text-center animate-fade-in">
          <div className="w-14 h-14 rounded-full bg-surface-800 flex items-center justify-center mb-4">
            <Search className="w-6 h-6 text-surface-500" />
          </div>
          <p className="text-sm text-surface-400 max-w-md">
            Enter a CID to browse IPFS content — directory listings, file previews, and pin management
          </p>
        </div>
      )}

      {/* Resolving IPNS — skeleton */}
      {state === 'resolving' && (
        <div className="glass rounded-xl p-8 animate-fade-in">
          <div className="flex items-center gap-3 mb-6">
            <Skeleton className="h-5 w-48" />
            <Skeleton className="h-5 w-28" />
          </div>
          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
            {Array.from({ length: 3 }).map((_, i) => (
              <div key={i} className="glass rounded-xl p-5 space-y-3">
                <Skeleton className="h-3 w-20" />
                <Skeleton className="h-7 w-48" />
                <Skeleton className="h-2 w-full" />
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Error state */}
      {state === 'error' && (
        <div className="glass rounded-xl p-6 animate-fade-in border border-accent-rose/20">
          <div className="flex items-start gap-3">
            <AlertCircle className="w-5 h-5 text-accent-rose shrink-0 mt-0.5" />
            <div className="flex-1 min-w-0">
              <p className="text-sm font-medium text-accent-rose mb-1">
                Failed to browse content
              </p>
              <p className="text-xs text-surface-400 break-all">{error}</p>
            </div>
            <button
              onClick={handleRetry}
              className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-surface-800 text-xs text-surface-300 hover:bg-surface-700 transition-colors shrink-0"
            >
              <RefreshCw className="w-3.5 h-3.5" />
              Retry
            </button>
          </div>
        </div>
      )}

      {/* Loaded state — breadcrumbs + directory listing */}
      {(state === 'loaded' || state === 'loading') && (
        <div className="space-y-4 animate-fade-in">
          {/* Breadcrumbs + Pin + Gateway row */}
          <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
            <Breadcrumbs
              path={[{ cid, name: cid.slice(0, 12) + '…' }, ...path]}
              onNavigate={handleBreadcrumbNavigate}
            />
            <div className="flex items-center gap-3 shrink-0">
              <GatewayLink cid={cid} />
              <PinBadge cid={cid} isPinned={pins.includes(cid)} onPin={handlePinToggle} />
            </div>
          </div>

          {/* Directory listing */}
          <DirectoryListing
            entries={entries}
            loading={state === 'loading'}
            onNavigate={handleNavigate}
            onPreview={handlePreview}
            pins={pins}
          />

          {/* File preview */}
          {previewCid && (
            <FilePreview
              cid={previewCid}
              content={previewContent}
              loading={previewLoading}
              onClose={handleClosePreview}
              filename={findFilename(entries, previewCid)}
            />
          )}
        </div>
      )}
      </ErrorBoundary>
    </PortalLayout>
  );
}


