import { useEffect, useMemo, useState } from 'react';
import { ArrowLeft, BrainCircuit, CalendarDays, CloudMoon } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { api } from '@/api/client';
import type { MemoryEntry, DailyMemoryEntry, DreamEntry } from '@/api/types';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { useSidebar } from '@/hooks/useSidebar';
import { cn } from '@/lib/utils';

function useFetch<T>(fetcher: () => Promise<T>): {
  data: T | null;
  loading: boolean;
  error: string | null;
  retry: () => void;
} {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  function load() {
    setLoading(true);
    setError(null);
    fetcher()
      .then(setData)
      .catch((err: unknown) => {
        setError(err instanceof Error ? err.message : 'failed to load data');
      })
      .finally(() => setLoading(false));
  }

  useEffect(() => { load(); }, []); // eslint-disable-line react-hooks/exhaustive-deps

  return { data, loading, error, retry: load };
}

function SkeletonBar({ className }: { className?: string }) {
  return <div className={cn('animate-pulse rounded bg-muted/40', className)} />;
}

function formatDate(iso: string | null | undefined): string {
  if (!iso) return '—';
  return new Date(iso).toLocaleDateString(undefined, {
    month: 'short',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function formatDateShort(iso: string | null | undefined): string {
  if (!iso) return '—';
  return new Date(iso).toLocaleDateString(undefined, {
    month: 'short',
    day: 'numeric',
    year: 'numeric',
  });
}

function truncate(str: string, max: number): string {
  if (str.length <= max) return str;
  return str.slice(0, max) + '…';
}


function EmptyState({ message }: { message: string }) {
  return <p className="text-sm text-muted-foreground py-8 text-center">{message}</p>;
}

type TabId = 'all' | 'daily' | 'dreams';

function TabBar({ active, onChange }: { active: TabId; onChange: (t: TabId) => void }) {
  return (
    <div className="flex gap-1 border-b pb-px">
      {[
        { id: 'all' as TabId, label: 'All Memory', icon: BrainCircuit },
        { id: 'daily' as TabId, label: 'Daily Log', icon: CalendarDays },
        { id: 'dreams' as TabId, label: 'Dreams', icon: CloudMoon },
      ].map((tab) => (
        <button
          key={tab.id}
          type="button"
          onClick={() => onChange(tab.id)}
          className={cn(
            'flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-t-md border border-b-0 -mb-px transition-colors',
            active === tab.id
              ? 'bg-background border-border text-foreground'
              : 'border-transparent text-muted-foreground hover:text-foreground hover:bg-muted/30',
          )}
        >
          <tab.icon className="size-3.5" />
          <span>{tab.label}</span>
        </button>
      ))}
    </div>
  );
}

function AllMemoryTab({ projectId }: { projectId: string }) {
  const { data, loading, error, retry } = useFetch(() => api.memory.list(projectId).then((r) => r.entries));
  const [expanded, setExpanded] = useState<string | null>(null);

  if (loading) {
    return (
      <div className="pt-4 space-y-3">
        {[0, 1, 2].map((i) => (
          <Card key={i} size="sm">
            <CardContent className="pt-4 space-y-2">
              <SkeletonBar className="h-4 w-16" />
              <SkeletonBar className="h-5 w-3/4" />
              <SkeletonBar className="h-3 w-full" />
              <div className="flex gap-1.5">
                <SkeletonBar className="h-4 w-12" />
                <SkeletonBar className="h-4 w-16" />
              </div>
            </CardContent>
          </Card>
        ))}
      </div>
    );
  }

  if (error) {
    return (
      <div className="flex items-center gap-3 text-sm pt-4">
        <span className="text-destructive">{error}</span>
        <Button size="sm" variant="outline" onClick={retry}>
          Retry
        </Button>
      </div>
    );
  }

  if (!data || data.length === 0) {
    return <EmptyState message="No topic-based memory entries yet." />;
  }

  return (
    <div className="pt-4 space-y-3">
      {data.map((entry: MemoryEntry) => (
        <Card key={entry.id}>
          <CardContent className="pt-4">
            <button
              type="button"
              onClick={() => setExpanded(expanded === entry.id ? null : entry.id)}
              className="w-full text-left"
            >
              {/* Topic badge */}
              <span className="inline-block text-[10px] uppercase tracking-wider font-medium text-muted-foreground bg-muted/50 px-1.5 py-0.5 rounded mb-1.5">
                {entry.topic}
              </span>
              <h3 className="text-sm font-medium">{entry.title}</h3>
              <p className="text-xs text-muted-foreground mt-1 line-clamp-2">
                {truncate(entry.content, 200)}
              </p>
              {entry.tags.length > 0 && (
                <div className="flex flex-wrap gap-1 mt-2">
                  {entry.tags.map((tag) => (
                    <span
                      key={tag}
                      className="text-[10px] bg-secondary/50 text-secondary-foreground px-1.5 py-0.5 rounded"
                    >
                      {tag}
                    </span>
                  ))}
                </div>
              )}
            </button>
            {expanded === entry.id && (
              <div className="mt-3 pt-3 border-t text-xs text-foreground/80 leading-relaxed whitespace-pre-wrap">
                {entry.content}
              </div>
            )}
          </CardContent>
        </Card>
      ))}
    </div>
  );
}

function DailyLogTab({ projectId }: { projectId: string }) {
  const { data, loading, error, retry } = useFetch(() => api.memory.daily(projectId).then((r) => r.entries));
  const [expanded, setExpanded] = useState<string | null>(null);

  const grouped = useMemo(() => {
    if (!data) return [];
    const groups: Record<string, DailyMemoryEntry[]> = {};
    for (const entry of data) {
      const g = groups[entry.date];
      if (g) {
        g.push(entry);
      } else {
        groups[entry.date] = [entry];
      }
    }
    return Object.entries(groups).sort((a, b) => b[0].localeCompare(a[0]));
  }, [data]);

  if (loading) {
    return (
      <div className="pt-4 space-y-4">
        {[0, 1].map((day) => (
          <div key={day}>
            <SkeletonBar className="h-4 w-24 mb-2" />
            <div className="space-y-2">
              {[0, 1].map((e) => (
                <Card key={e} size="sm">
                  <CardContent className="pt-3 space-y-1">
                    <SkeletonBar className="h-3 w-20" />
                    <SkeletonBar className="h-3 w-full" />
                  </CardContent>
                </Card>
              ))}
            </div>
          </div>
        ))}
      </div>
    );
  }

  if (error) {
    return (
      <div className="flex items-center gap-3 text-sm pt-4">
        <span className="text-destructive">{error}</span>
        <Button size="sm" variant="outline" onClick={retry}>
          Retry
        </Button>
      </div>
    );
  }

  if (!data || data.length === 0) {
    return <EmptyState message="No daily log entries for the last 7 days." />;
  }

  return (
    <div className="pt-4 space-y-4">
      {grouped.map(([date, entries]) => (
        <div key={date}>
          <h3 className="text-sm font-medium text-muted-foreground mb-2">
            {formatDateShort(date)}
          </h3>
          <div className="space-y-2">
            {entries.map((entry: DailyMemoryEntry) => (
              <Card key={entry.id} size="sm">
                <CardContent className="pt-3">
                  <button
                    type="button"
                    onClick={() => setExpanded(expanded === entry.id ? null : entry.id)}
                    className="w-full text-left"
                  >
                    <span className="text-xs font-mono text-muted-foreground">
                      {entry.title}
                    </span>
                    <p className="text-xs text-muted-foreground mt-1 line-clamp-1">
                      {truncate(entry.content, 150)}
                    </p>
                  </button>
                  {expanded === entry.id && (
                    <div className="mt-2 pt-2 border-t text-xs text-foreground/80 leading-relaxed whitespace-pre-wrap">
                      {entry.content}
                    </div>
                  )}
                </CardContent>
              </Card>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

function DreamsTab({ projectId }: { projectId: string }) {
  const { data, loading, error, retry } = useFetch(() => api.memory.dreams(projectId).then((r) => r.entries));

  if (loading) {
    return (
      <div className="pt-4 space-y-3">
        {[0, 1, 2].map((i) => (
          <Card key={i}>
            <CardContent className="pt-4 space-y-2">
              <SkeletonBar className="h-4 w-32" />
              <SkeletonBar className="h-3 w-full" />
              <SkeletonBar className="h-3 w-5/6" />
              <SkeletonBar className="h-3 w-2/3" />
            </CardContent>
          </Card>
        ))}
      </div>
    );
  }

  if (error) {
    return (
      <div className="flex items-center gap-3 text-sm pt-4">
        <span className="text-destructive">{error}</span>
        <Button size="sm" variant="outline" onClick={retry}>
          Retry
        </Button>
      </div>
    );
  }

  if (!data || data.length === 0) {
    return <EmptyState message="No dream consolidation diaries yet." />;
  }

  return (
    <div className="pt-4 space-y-3">
      {data.map((entry: DreamEntry, i: number) => (
        <Card key={i}>
          <CardContent className="pt-4">
            <h3 className="text-sm font-medium mb-2">{formatDateShort(entry.date)}</h3>
            <pre className="text-xs font-mono leading-relaxed whitespace-pre-wrap bg-muted/20 p-3 rounded-md border border-border/50 overflow-x-auto">
              {entry.content}
            </pre>
          </CardContent>
        </Card>
      ))}
    </div>
  );
}

export function Memory() {
  const navigate = useNavigate();
  const { data: sidebar, activeSession } = useSidebar();

  const [tab, setTab] = useState<TabId>('all');
  const [projectId, setProjectId] = useState<string | null>(null);

  // Derive default project from active session or first project.
  const projects = useMemo(() => {
    return sidebar?.projects?.map((p: { id: string; name: string }) => p) ?? [];
  }, [sidebar]);

  useEffect(() => {
    if (!projectId && projects.length > 0) {
      // Prefer active session's project, else first project.
      const defaultId = activeSession?.project_id ?? projects[0]!.id;
      setProjectId(defaultId);
    }
  }, [projects, activeSession, projectId]);

  function handleBack() {
    if (window.history.length > 1) {
      navigate(-1);
    } else {
      navigate('/');
    }
  }

  return (
    <div className="flex-1 overflow-y-auto">
      <div className="max-w-[1000px] mx-auto w-full px-6 py-6 space-y-6">
        {/* Header */}
        <header className="space-y-2">
          <button
            type="button"
            onClick={handleBack}
            className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground -ml-1 px-1 py-0.5 rounded"
            aria-label="Back"
          >
            <ArrowLeft className="size-4" />
            <span>Back</span>
          </button>
          <div className="flex items-center justify-between gap-4">
            <div>
              <h1 className="text-xl font-semibold flex items-center gap-2">
                <BrainCircuit className="size-5" />
                Memory Browser
              </h1>
              <p className="text-sm text-muted-foreground mt-1">
                Topic-based memories, daily logs, and dream consolidation diaries.
              </p>
            </div>
            </div>
          {/* Project selector */}
          <select
            value={projectId ?? ''}
            onChange={(e) => setProjectId(e.target.value)}
            className="w-full rounded-md border border-input bg-background px-3 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
          >
            {projects.map((p) => (
              <option key={p.id} value={p.id}>
                {p.name}
              </option>
            ))}
          </select>
        </header>

        {/* Tab bar */}
        <TabBar active={tab} onChange={setTab} />

        {/* Tab content */}
        {!projectId ? (
          <EmptyState message="Select a project to view memory." />
        ) : tab === 'all' ? (
          <AllMemoryTab projectId={projectId} />
        ) : tab === 'daily' ? (
          <DailyLogTab projectId={projectId} />
        ) : (
          <DreamsTab projectId={projectId} />
        )}
      </div>
    </div>
  );
}
