import { useCallback, useEffect, useState } from 'react';
import { Archive, ChevronLeft, Code, MessageSquare, RotateCcw, Terminal, Trash2 } from 'lucide-react';
import { toast } from 'sonner';
import mascot from '@/assets/brand/banner-mascot.png';
import { EmptyState } from '@/components/EmptyState';
import { ChatInput } from '@/components/ChatInput';
import { Button } from '@/components/ui/button';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { api } from '@/api/client';
import type { Chat } from '@/api/types';
import { formatRelative } from '@/lib/format';

interface Props {
  projectId: string;
  sessionId: string;
  agentId?: string | null;
  onAgentChange?: (agentId: string | null) => void | Promise<void>;
  onSend: (content: string) => void;
  // Slash-command (skill) send from the landing page. The parent creates the
  // chat, assigns it to the pane (so it transitions to ChatPane), and invokes
  // the skill — same transition the text send uses. See useSessionChats.
  onSkillInvoke: (skillName: string, userMessage: string | null) => void;
  createChat: () => Promise<{ id: string }>;
  // Session history: the session's open chats (live), and callbacks to open one
  // in THIS pane / restore an archived one. Archived chats are fetched here
  // (the default open-only list excludes them).
  chats: Chat[];
  onOpenChat: (chatId: string) => void;
  onUnarchiveChat: (chatId: string) => Promise<void>;
  onArchiveChat: (chatId: string) => Promise<void>;
  onDeleteChat: (chatId: string) => Promise<void>;
  // Controlled session-history view: the new-chat hero is the default; the
  // header's "Session history" button flips this on (and Back flips it off).
  openHistory: boolean;
  onCloseHistory: () => void;
}


function byRecent(a: Chat, b: Chat): number {
  return (b.updated_at ?? '').localeCompare(a.updated_at ?? '');
}

// Pick the row icon by the chat's seed name: coder and terminal panes create
// placeholder chats named 'BooCoder' / 'Terminal' (see useWorkspacePanes
// chatNameForPaneKind + the coder chat-resolve). A name heuristic keeps this
// frontend-only — matches ProjectSidebar's isCoderSessionName approach.
function iconForChat(name: string | null) {
  if (name === 'BooCoder') return Code;
  if (name === 'Terminal') return Terminal;
  return MessageSquare;
}

export function SessionLandingPage({
  projectId,
  sessionId,
  agentId,
  onAgentChange,
  onSend,
  onSkillInvoke,
  createChat,
  chats,
  onOpenChat,
  onUnarchiveChat,
  onArchiveChat,
  onDeleteChat,
  openHistory,
  onCloseHistory,
}: Props) {
  const [chatId, setChatId] = useState<string | null>(null);
  const [archived, setArchived] = useState<Chat[]>([]);
  // Plain Cancel/Confirm delete (no type-to-confirm), mirroring ProjectSidebar.
  const [deleteConfirm, setDeleteConfirm] = useState<{ id: string; name: string | null } | null>(null);

  // Archived chats aren't in the default (open-only) list, so fetch them. One
  // shot on session change — the history view is transient (pick a chat and
  // it's gone), so slight staleness is fine; reopening the pane refetches.
  useEffect(() => {
    let cancelled = false;
    api.chats
      .listForSession(sessionId, { status: 'archived' })
      .then((list) => { if (!cancelled) setArchived(list); })
      .catch(() => {});
    return () => { cancelled = true; };
  }, [sessionId]);

  const ensureChat = useCallback(async (): Promise<string> => {
    if (chatId) return chatId;
    try {
      const chat = await createChat();
      setChatId(chat.id);
      return chat.id;
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Failed to create chat');
      throw err;
    }
  }, [chatId, createChat]);

  const handleSend = useCallback(async (content: string) => {
    const text = content.trim();
    if (!text) return;
    try {
      await ensureChat();
      onSend(text);
    } catch {
      // Error already surfaced via toast.
    }
  }, [ensureChat, onSend]);

  // Route to the parent, which creates the chat, assigns it to the pane (so the
  // pane transitions to ChatPane and subscribes to the stream), then invokes the
  // skill — mirroring the text-send transition. Doing the skill invoke locally
  // (without the pane assignment) left the landing pane stuck/blank.
  const handleSlashCommand = useCallback((skillName: string, userMessage: string) => {
    onSkillInvoke(skillName, userMessage.length > 0 ? userMessage : null);
  }, [onSkillInvoke]);

  const restoreAndOpen = useCallback(async (id: string) => {
    try {
      await onUnarchiveChat(id);
      onOpenChat(id);
    } catch {
      // onUnarchiveChat surfaces its own toast.
    }
  }, [onUnarchiveChat, onOpenChat]);

  const openChats = [...chats.filter((c) => c.status === 'open')].sort(byRecent);
  const openIds = new Set(openChats.map((c) => c.id));
  const archivedChats = archived.filter((c) => !openIds.has(c.id)).sort(byRecent);
  const isEmpty = openChats.length === 0 && archivedChats.length === 0;

  return (
    <div className="flex flex-col h-full min-h-0">
      <div className="flex-1 min-h-0 overflow-y-auto">
        <div className="max-w-[760px] mx-auto w-full px-4 py-4 h-full">
          {!openHistory ? (
            /* Landing hero — BooCode mascot + prompt, vertically centered to
               match the coder pane's empty state (a flex-1 fill).
               Session history lives in the header (see Session.tsx row 2). */
            <div className="flex flex-col items-center justify-center text-center gap-4 h-full">
              <img
                src={mascot}
                alt="BooCode"
                draggable={false}
                className="w-20 h-auto select-none"
              />
              <p className="text-sm text-muted-foreground">
                Send a message to start a new conversation
              </p>
            </div>
          ) : (
            <>
              <div className="flex items-center gap-1.5 mb-3">
                <button
                  type="button"
                  onClick={onCloseHistory}
                  className="inline-flex items-center gap-1 -ml-1 px-2 min-h-[44px] rounded text-sm text-muted-foreground hover:text-foreground hover:bg-muted/60"
                  aria-label="Back to new conversation"
                >
                  <ChevronLeft size={16} className="shrink-0" />
                  Back
                </button>
                <h2 className="text-sm font-medium ml-auto mr-1">Session history</h2>
              </div>
              {isEmpty ? (
                <EmptyState
                  icon={<MessageSquare size={40} strokeWidth={1.5} />}
                  title="No conversations"
                  description="Your chat history will appear here"
                />
              ) : (<>
              {openChats.length > 0 && (
                <>
                  <h3 className="text-xs font-medium uppercase tracking-wide text-muted-foreground px-1 mb-1.5">
                    Conversations
                  </h3>
                  <div className="space-y-0.5 mb-4">
                    {openChats.map((c) => {
                      const Icon = iconForChat(c.name);
                      return (
                        <div
                          key={c.id}
                          className="group/row flex items-center gap-2 px-2 py-1.5 rounded hover:bg-muted text-sm max-md:min-h-[44px]"
                        >
                          <button
                            type="button"
                            onClick={() => onOpenChat(c.id)}
                            className="flex items-center gap-2 flex-1 min-w-0 text-left"
                          >
                            <Icon size={14} className="shrink-0 text-muted-foreground" />
                            <span className="truncate shrink-0 max-w-[45%]">{c.name ?? 'New chat'}</span>
                            {c.last_message_preview && (
                              <span className="truncate flex-1 text-xs text-muted-foreground hidden sm:block">
                                {c.last_message_preview}
                              </span>
                            )}
                            <span className="shrink-0 ml-auto text-xs text-muted-foreground">
                              {formatRelative(c.updated_at)}
                            </span>
                          </button>
                          <div className="shrink-0 flex items-center gap-0.5 opacity-0 group-hover/row:opacity-100 focus-within:opacity-100 max-md:opacity-100 motion-reduce:transition-none transition-opacity">
                            <button
                              type="button"
                              onClick={(e) => { e.stopPropagation(); void onArchiveChat(c.id); }}
                              className="inline-flex items-center justify-center size-7 rounded text-muted-foreground hover:bg-muted hover:text-foreground max-md:size-9"
                              aria-label="Archive chat"
                              title="Archive"
                            >
                              <Archive size={14} />
                            </button>
                            <button
                              type="button"
                              onClick={(e) => { e.stopPropagation(); setDeleteConfirm({ id: c.id, name: c.name }); }}
                              className="inline-flex items-center justify-center size-7 rounded text-muted-foreground hover:bg-destructive/20 hover:text-destructive max-md:size-9"
                              aria-label="Delete chat"
                              title="Delete"
                            >
                              <Trash2 size={14} />
                            </button>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </>
              )}
              {archivedChats.length > 0 && (
                <>
                  <h3 className="text-xs font-medium uppercase tracking-wide text-muted-foreground px-1 mb-1.5">
                    Archived
                  </h3>
                  <div className="space-y-0.5">
                    {archivedChats.map((c) => (
                      <div
                        key={c.id}
                        className="group/arch flex items-center gap-2 px-2 py-1.5 rounded hover:bg-muted text-sm text-muted-foreground max-md:min-h-[44px]"
                      >
                        <button
                          type="button"
                          onClick={() => void restoreAndOpen(c.id)}
                          title="Restore and open"
                          className="flex items-center gap-2 flex-1 min-w-0 text-left"
                        >
                          <Archive size={14} className="shrink-0" />
                          <span className="truncate flex-1">{c.name ?? 'New chat'}</span>
                          <span className="shrink-0 text-xs">{formatRelative(c.updated_at)}</span>
                          <RotateCcw
                            size={13}
                            className="shrink-0 opacity-0 group-hover/arch:opacity-100 max-md:opacity-100"
                          />
                        </button>
                        <button
                          type="button"
                          onClick={(e) => { e.stopPropagation(); setDeleteConfirm({ id: c.id, name: c.name }); }}
                          className="shrink-0 inline-flex items-center justify-center size-7 rounded hover:bg-destructive/20 hover:text-destructive max-md:size-9 opacity-0 group-hover/arch:opacity-100 focus-within:opacity-100 max-md:opacity-100 motion-reduce:transition-none transition-opacity"
                          aria-label="Delete chat"
                          title="Delete"
                        >
                          <Trash2 size={14} />
                        </button>
                      </div>
                    ))}
                  </div>
                </>
              )}
              </>)}
            </>
          )}
        </div>
      </div>
      <ChatInput
        disabled={false}
        projectId={projectId}
        sessionId={sessionId}
        agentId={agentId ?? null}
        onAgentChange={onAgentChange}
        onSend={handleSend}
        onSlashCommand={handleSlashCommand}
        chatId={chatId ?? undefined}
        chatLabel="Chat"
        messages={[]}
        modelContextLimit={null}
      />
      <Dialog
        open={deleteConfirm !== null}
        onOpenChange={(open) => { if (!open) setDeleteConfirm(null); }}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Delete chat?</DialogTitle>
            <DialogDescription>
              Permanently deletes "{deleteConfirm?.name ?? 'New chat'}" and all its messages. This cannot be undone.
            </DialogDescription>
          </DialogHeader>
          <div className="flex gap-2 justify-end pt-2">
            <Button variant="outline" onClick={() => setDeleteConfirm(null)}>Cancel</Button>
            <Button
              variant="destructive"
              onClick={() => {
                if (deleteConfirm) void onDeleteChat(deleteConfirm.id);
                setDeleteConfirm(null);
              }}
            >
              Delete
            </Button>
          </div>
        </DialogContent>
      </Dialog>
    </div>
  );
}
