import { memo } from "preact/compat";
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
import {
  getCardLiveContent,
  hasCardRefreshHandler,
  runCardRefresh,
  subscribeCardLiveContent,
} from "../cardRuntime/store";
import type { CardItem, JsonValue } from "../types";
import { DynamicCardBody } from "./CardBodyRenderer";
import { captureInboxItem, InboxQuickAdd, InboxReviewCard } from "./cardFeed/inbox";
import { snoozeCardUntilTomorrow } from "./cardFeed/snooze";

interface CardProps {
  card: CardItem;
  onDismiss(id: number): void;
  onChoice(cardId: string, value: string): void;
  onAskCard(card: CardItem): void;
}

function MoreIcon() {
  return (
    <svg viewBox="0 0 24 24" aria-hidden="true">
      <circle cx="6" cy="12" r="1.75" fill="currentColor" />
      <circle cx="12" cy="12" r="1.75" fill="currentColor" />
      <circle cx="18" cy="12" r="1.75" fill="currentColor" />
    </svg>
  );
}

function CardQuestionBody({
  card,
  responding,
  onChoice,
}: {
  card: CardItem;
  responding: boolean;
  onChoice(cardId: string, value: string): void;
}) {
  const canAnswer = card.state === "active" && !responding && !!card.serverId;

  return (
    <>
      {card.content && <div class="card-body">{card.content}</div>}
      <div class="card-question">{card.question}</div>
      <div class="card-choices">
        {(card.choices ?? []).map((label) => (
          <button
            key={label}
            class="card-choice-btn"
            type="button"
            disabled={!canAnswer}
            onClick={(e) => {
              e.stopPropagation();
              if (!card.serverId) return;
              onChoice(card.serverId, label);
            }}
          >
            {label}
          </button>
        ))}
      </div>
      {card.responseValue && <div class="card-response">Selected: {card.responseValue}</div>}
    </>
  );
}

// biome-ignore lint/complexity/noExcessiveLinesPerFunction: card header still owns the menu actions in one place
function CardHeader({
  card,
  onDismiss,
  onAskCard,
  onSnooze,
}: {
  card: CardItem;
  onDismiss(): void;
  onAskCard(card: CardItem): void;
  onSnooze(card: CardItem): void;
}) {
  const [menuOpen, setMenuOpen] = useState(false);
  const menuRef = useRef<HTMLDivElement>(null);
  const canRefresh =
    card.kind === "text" &&
    !!card.serverId &&
    (card.templateKey === "git-diff-live" || hasCardRefreshHandler(card.serverId));
  const canSnooze = card.kind === "text" && card.templateKey === "upcoming-conditions-live";

  useEffect(() => {
    if (!menuOpen) return;

    const handlePointerDown = (event: PointerEvent) => {
      if (!(event.target instanceof Node)) return;
      if (menuRef.current?.contains(event.target)) return;
      setMenuOpen(false);
    };

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") setMenuOpen(false);
    };

    document.addEventListener("pointerdown", handlePointerDown);
    document.addEventListener("keydown", handleKeyDown);
    return () => {
      document.removeEventListener("pointerdown", handlePointerDown);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [menuOpen]);

  return (
    <header class={`card-header${card.kind === "text" ? " floating" : ""}`}>
      {card.kind !== "text" && (
        <div class="card-title-wrap">
          <div class="card-title-line">
            {card.title && <span class="card-title">{card.title}</span>}
          </div>
          <div class="card-meta">
            {card.state !== "active" && (
              <span class={`card-state state-${card.state}`}>{card.state}</span>
            )}
          </div>
        </div>
      )}
      <div ref={menuRef} class="card-menu-wrap">
        <button
          class={`card-menu-trigger${menuOpen ? " open" : ""}`}
          type="button"
          aria-label="Card actions"
          aria-expanded={menuOpen}
          onClick={(e) => {
            e.stopPropagation();
            setMenuOpen((current) => !current);
          }}
        >
          <MoreIcon />
        </button>
        {menuOpen && (
          <div class="card-menu" role="menu">
            {canRefresh && (
              <button
                class="card-menu-item"
                type="button"
                role="menuitem"
                onClick={(e) => {
                  e.stopPropagation();
                  setMenuOpen(false);
                  if (!card.serverId) return;
                  runCardRefresh(card.serverId);
                }}
              >
                Refresh
              </button>
            )}
            {card.kind === "text" && (
              <button
                class="card-menu-item"
                type="button"
                role="menuitem"
                onClick={(e) => {
                  e.stopPropagation();
                  setMenuOpen(false);
                  onAskCard(card);
                }}
              >
                Ask Nanobot
              </button>
            )}
            {canSnooze && (
              <button
                class="card-menu-item"
                type="button"
                role="menuitem"
                onClick={(e) => {
                  e.stopPropagation();
                  setMenuOpen(false);
                  onSnooze(card);
                }}
              >
                Snooze until tomorrow
              </button>
            )}
            <button
              class="card-menu-item danger"
              type="button"
              role="menuitem"
              onClick={(e) => {
                e.stopPropagation();
                setMenuOpen(false);
                onDismiss();
              }}
            >
              Dismiss
            </button>
          </div>
        )}
      </div>
    </header>
  );
}

function CardInner({
  card,
  onDismiss,
  onChoice,
  onAskCard,
  onSnooze,
}: CardProps & { onSnooze(card: CardItem): void }) {
  const [dismissing, setDismissing] = useState(false);
  const [responding, setResponding] = useState(false);
  const [liveContent, setLiveContentState] = useState<JsonValue | undefined>(() =>
    card.serverId ? getCardLiveContent(card.serverId) : undefined,
  );
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const isHelperCard =
    (card.serverId ?? "").startsWith("task-helper-") || (card.slot ?? "").startsWith("taskhelper:");
  const alertOnly =
    !!card.templateState &&
    typeof card.templateState === "object" &&
    !Array.isArray(card.templateState) &&
    card.templateState.alert_only === true;
  const hiddenByLiveContent =
    alertOnly && liveContent === undefined
      ? true
      : !!liveContent &&
        typeof liveContent === "object" &&
        !Array.isArray(liveContent) &&
        (liveContent as Record<string, unknown>).hidden === true;

  useEffect(() => {
    return () => {
      if (timerRef.current) clearTimeout(timerRef.current);
    };
  }, []);

  useEffect(() => {
    setLiveContentState(card.serverId ? getCardLiveContent(card.serverId) : undefined);
    if (!card.serverId) return;
    return subscribeCardLiveContent((changedCardId, snapshot) => {
      if (changedCardId !== card.serverId) return;
      setLiveContentState(snapshot);
    });
  }, [card.serverId]);

  useEffect(() => {
    if (card.state !== "active") setResponding(false);
  }, [card.state]);

  const dismiss = () => {
    if (dismissing) return;
    setDismissing(true);
    timerRef.current = setTimeout(() => onDismiss(card.id), 220);
  };

  return (
    <article
      class={`card kind-${card.kind}${isHelperCard ? " helper-card" : ""}${dismissing ? " dismissing" : ""}${hiddenByLiveContent ? " is-hidden-live" : ""} state-${card.state}`}
    >
      <CardHeader card={card} onDismiss={dismiss} onAskCard={onAskCard} onSnooze={onSnooze} />
      {card.kind === "text" ? (
        <DynamicCardBody item={card} surface="feed" />
      ) : (
        <CardQuestionBody
          card={card}
          responding={responding}
          onChoice={(cardId, value) => {
            setResponding(true);
            onChoice(cardId, value);
          }}
        />
      )}
      {card.contextSummary && card.kind !== "text" && (
        <footer class="card-footer">{card.contextSummary}</footer>
      )}
    </article>
  );
}

const Card = memo(
  CardInner,
  (prev, next) =>
    prev.card === next.card &&
    prev.onDismiss === next.onDismiss &&
    prev.onChoice === next.onChoice &&
    prev.onAskCard === next.onAskCard &&
    prev.onSnooze === next.onSnooze,
);

interface CardFeedProps {
  cards: CardItem[];
  viewActive: boolean;
  onDismiss(id: number): void;
  onChoice(cardId: string, value: string): void;
  onAskCard(card: CardItem): void;
}

export function CardFeed({ cards, viewActive, onDismiss, onChoice, onAskCard }: CardFeedProps) {
  const handleSnooze = useCallback((targetCard: CardItem) => {
    void snoozeCardUntilTomorrow(targetCard.serverId).catch((error) => {
      console.error("Card snooze failed", error);
    });
  }, []);

  return (
    <div class="card-feed-shell">
      <div id="card-feed" class={viewActive ? "feed-view" : ""}>
        <InboxReviewCard />
        {cards.map((card) => (
          <Card
            key={card.id}
            card={card}
            onDismiss={onDismiss}
            onChoice={onChoice}
            onAskCard={onAskCard}
            onSnooze={handleSnooze}
          />
        ))}
      </div>
      <InboxQuickAdd
        visible={viewActive}
        onSubmit={async (text) => {
          await captureInboxItem(text);
        }}
      />
    </div>
  );
}
