import { useCallback, useEffect, useRef, useState } from "preact/hooks";
import type { LogLine } from "../types";

interface Props {
  lines: LogLine[];
  disabled: boolean;
  onSendMessage(text: string): Promise<void>;
  onExpandChange?(expanded: boolean): void;
}

interface LogViewProps {
  lines: LogLine[];
  scrollRef: { current: HTMLElement | null };
}

function SendIcon() {
  return (
    <svg width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true">
      <path d="M2 9L16 2L9.5 16L8 10.5L2 9Z" fill="currentColor" />
    </svg>
  );
}

function CloseIcon() {
  return (
    <svg width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true">
      <path d="M14 4L4 14M4 4L14 14" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
    </svg>
  );
}

function formatLine(line: LogLine): string {
  const time = line.timestamp ? new Date(line.timestamp).toLocaleTimeString() : "";
  const role = line.role.trim().toLowerCase();
  if (role === "nanobot") {
    return `[${time}] ${line.text.replace(/^(?:nanobot|napbot)\b\s*[:>-]?\s*/i, "")}`;
  }
  if (role === "tool") {
    return `[${time}] tool: ${line.text}`;
  }
  return `[${time}] ${line.role}: ${line.text}`;
}

function LogCompose({
  disabled,
  sending,
  text,
  setText,
  onClose,
  onSend,
}: {
  disabled: boolean;
  sending: boolean;
  text: string;
  setText(value: string): void;
  onClose(): void;
  onSend(): void;
}) {
  const onKeyDown = useCallback(
    (e: KeyboardEvent) => {
      if (e.key === "Enter" && !e.shiftKey) {
        e.preventDefault();
        onSend();
      }
      if (e.key === "Escape") {
        e.preventDefault();
        onClose();
      }
    },
    [onClose, onSend],
  );

  return (
    <div id="log-compose">
      <textarea
        id="log-compose-input"
        placeholder="Type a message to nanobot..."
        disabled={disabled || sending}
        value={text}
        onInput={(e) => setText((e.target as HTMLTextAreaElement).value)}
        onKeyDown={onKeyDown}
      />
      <div id="log-compose-actions">
        <button id="log-close-btn" type="button" aria-label="Close" onClick={onClose}>
          <CloseIcon />
        </button>
        <button
          id="log-send-btn"
          type="button"
          aria-label="Send message"
          disabled={disabled || sending || text.trim().length === 0}
          onClick={onSend}
        >
          <SendIcon />
        </button>
      </div>
    </div>
  );
}

function ExpandedLogView({ lines, scrollRef }: LogViewProps) {
  return (
    <div
      id="log-scroll"
      ref={(node) => {
        scrollRef.current = node;
      }}
    >
      <div id="log-inner">
        {lines.map((line) => (
          <div key={line.id} class={`line ${line.role}`}>
            {formatLine(line)}
          </div>
        ))}
      </div>
    </div>
  );
}

function CollapsedLogView({ lines, scrollRef, onExpand }: LogViewProps & { onExpand(): void }) {
  return (
    <button
      id="log-collapsed"
      ref={(node) => {
        scrollRef.current = node;
      }}
      type="button"
      aria-label="Open message composer"
      onClick={onExpand}
    >
      <div id="log-inner">
        {lines.map((line) => (
          <span key={line.id} class={`line ${line.role}`}>
            {formatLine(line)}
          </span>
        ))}
      </div>
    </button>
  );
}

export function LogPanel({ lines, disabled, onSendMessage, onExpandChange }: Props) {
  const [expanded, setExpanded] = useState(false);
  const [text, setText] = useState("");
  const [sending, setSending] = useState(false);
  const scrollRef = useRef<HTMLElement>(null);

  useEffect(() => onExpandChange?.(expanded), [expanded, onExpandChange]);
  useEffect(() => () => onExpandChange?.(false), [onExpandChange]);
  useEffect(() => {
    const el = scrollRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [lines, expanded]);

  const collapse = useCallback(() => {
    setExpanded(false);
    setText("");
  }, []);

  const expand = useCallback(() => {
    if (!expanded) setExpanded(true);
  }, [expanded]);

  const send = useCallback(async () => {
    const message = text.trim();
    if (!message || sending || disabled) return;
    setSending(true);
    try {
      await onSendMessage(message);
      setText("");
    } catch (err) {
      window.alert(`Could not send message: ${String(err)}`);
    } finally {
      setSending(false);
    }
  }, [disabled, onSendMessage, sending, text]);

  return (
    <div id="log" class={expanded ? "expanded" : ""} data-no-swipe="1">
      {expanded ? (
        <ExpandedLogView lines={lines} scrollRef={scrollRef} />
      ) : (
        <CollapsedLogView lines={lines} scrollRef={scrollRef} onExpand={expand} />
      )}
      {expanded && (
        <LogCompose
          disabled={disabled}
          sending={sending}
          text={text}
          setText={setText}
          onClose={collapse}
          onSend={() => {
            void send();
          }}
        />
      )}
    </div>
  );
}
