import {
  useEffect,
  useRef,
  type KeyboardEvent,
  type RefObject,
} from 'react';
import { Button } from '@/components/ui/button';

const DIALOG_FOCUSABLE_SELECTOR = [
  'button:not([disabled])',
  'input:not([disabled])',
  'select:not([disabled])',
  'textarea:not([disabled])',
  '[tabindex]:not([tabindex="-1"])',
].join(',');

function useModalDialogFocus(
  open: boolean,
  dialogRef: RefObject<HTMLDivElement | null>,
  initialFocusRef: RefObject<HTMLElement | null>,
) {
  const previousFocusRef = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (!open) return undefined;
    previousFocusRef.current = document.activeElement instanceof HTMLElement
      ? document.activeElement
      : null;
    const dialog = dialogRef.current;
    (initialFocusRef.current
      ?? dialog?.querySelector<HTMLElement>(DIALOG_FOCUSABLE_SELECTOR))
      ?.focus();

    return () => {
      previousFocusRef.current?.focus();
      previousFocusRef.current = null;
    };
  }, [dialogRef, initialFocusRef, open]);
}

function handleModalKeyDown(
  event: KeyboardEvent<HTMLDivElement>,
  onCancel: () => void,
) {
  if (event.key === 'Escape') {
    event.preventDefault();
    event.stopPropagation();
    onCancel();
    return;
  }
  if (event.key !== 'Tab') return;

  const focusable = Array.from(
    event.currentTarget.querySelectorAll<HTMLElement>(
      DIALOG_FOCUSABLE_SELECTOR,
    ),
  );
  if (focusable.length === 0) {
    event.preventDefault();
    return;
  }
  const first = focusable[0];
  const last = focusable.at(-1) ?? first;
  if (event.shiftKey && document.activeElement === first) {
    event.preventDefault();
    last.focus();
  } else if (!event.shiftKey && document.activeElement === last) {
    event.preventDefault();
    first.focus();
  }
}

export interface ChatTimelineEntry {
  messageId: string;
  role: 'user' | 'assistant' | 'system' | 'toolresult';
  label: string;
  preview: string;
  timestamp?: number;
}

export interface ChatCommandRenameDialogProps {
  open: boolean;
  title: string;
  onTitleChange: (title: string) => void;
  onSubmit: (title: string) => void;
  onCancel: () => void;
}

export function ChatCommandRenameDialog({
  open,
  title,
  onTitleChange,
  onSubmit,
  onCancel,
}: ChatCommandRenameDialogProps) {
  const dialogRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  useModalDialogFocus(open, dialogRef, inputRef);

  if (!open) return null;
  const trimmedTitle = title.trim();
  return (
    <div
      ref={dialogRef}
      role="dialog"
      aria-modal="true"
      aria-labelledby="chat-rename-title"
      className="
        fixed inset-0 z-50 flex items-center justify-center bg-foreground/15
      "
      onKeyDown={(event) => handleModalKeyDown(event, onCancel)}
    >
      <form
        className="w-full max-w-md rounded-lg border bg-card p-6 shadow-lg"
        onSubmit={(event) => {
          event.preventDefault();
          if (trimmedTitle) onSubmit(trimmedTitle);
        }}
      >
        <h2 id="chat-rename-title" className="text-lg font-semibold">
          重命名会话
        </h2>
        <input
          ref={inputRef}
          aria-label="会话标题"
          value={title}
          className="mt-4 w-full rounded border px-3 py-2"
          onChange={(event) => onTitleChange(event.target.value)}
        />
        <div className="mt-6 flex justify-end gap-2">
          <Button type="button" variant="outline" onClick={onCancel}>
            取消
          </Button>
          <Button type="submit" disabled={!trimmedTitle}>
            重命名
          </Button>
        </div>
      </form>
    </div>
  );
}

export interface ChatCommandTimelineDialogProps {
  open: boolean;
  entries: readonly ChatTimelineEntry[];
  onSelect: (messageId: string) => void;
  onCancel: () => void;
}

export function ChatCommandTimelineDialog({
  open,
  entries,
  onSelect,
  onCancel,
}: ChatCommandTimelineDialogProps) {
  const dialogRef = useRef<HTMLDivElement>(null);
  const firstEntryRef = useRef<HTMLButtonElement>(null);
  useModalDialogFocus(open, dialogRef, firstEntryRef);

  if (!open) return null;
  const title = '消息时间线';
  return (
    <div
      ref={dialogRef}
      role="dialog"
      aria-modal="true"
      aria-labelledby="chat-timeline-title"
      className="
        fixed inset-0 z-50 flex items-center justify-center bg-foreground/15
      "
      onKeyDown={(event) => handleModalKeyDown(event, onCancel)}
    >
      <div
        className="
          max-h-[70vh] w-full max-w-xl overflow-y-auto rounded-lg border
          bg-card p-6 shadow-lg
        "
      >
        <h2 id="chat-timeline-title" className="text-lg font-semibold">
          {title}
        </h2>
        <div className="mt-4 space-y-2">
          {entries.map((entry) => (
            <button
              ref={entry === entries[0] ? firstEntryRef : undefined}
              key={entry.messageId}
              type="button"
              className="
                block w-full rounded border px-3 py-2 text-left
                hover:bg-muted
              "
              onClick={() => onSelect(entry.messageId)}
            >
              <span className="block text-xs font-medium text-muted-foreground">
                {entry.label}
              </span>
              <span className="block truncate">{entry.preview}</span>
            </button>
          ))}
        </div>
        <div className="mt-6 flex justify-end">
          <Button type="button" variant="outline" onClick={onCancel}>
            取消
          </Button>
        </div>
      </div>
    </div>
  );
}
