"use client";

import { useEffect, useMemo, useState } from "react";
import { MAX_CALL_PARTICIPANTS } from "@slackwsh/contracts";
import { avatarColor, initials } from "../lib/avatar";
import { IconPhone, IconVideo, IconX } from "./icons";

export interface NewCallModalMember {
  user: { id: string | number; name: string; email: string };
}

export interface NewCallSubmit {
  userIds: string[];
  kind: "audio" | "video";
  title: string;
}

const PRESENCE_LABEL: Record<string, string> = { active: "Online", away: "Away", offline: "Offline" };

/**
 * Who to call, and how. Reuses the shared .task-modal shell (same as
 * EventModal) rather than introducing a third dialog chrome.
 *
 * Presentational: it owns the selection and nothing else — the page starts the
 * call, so this never touches the api.
 */
export function NewCallModal({
  members,
  presence = {},
  busy,
  error,
  onClose,
  onSubmit,
}: {
  members: NewCallModalMember[];
  presence?: Record<string, { status: string }>;
  busy?: boolean;
  error?: string | null;
  onClose: () => void;
  onSubmit: (values: NewCallSubmit) => void;
}) {
  const [selected, setSelected] = useState<string[]>([]);
  const [kind, setKind] = useState<"audio" | "video">("audio");
  const [title, setTitle] = useState("");
  const [query, setQuery] = useState("");

  useEffect(() => {
    function onKey(e: KeyboardEvent) {
      if (e.key === "Escape") onClose();
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  // Online first, then alphabetical — you are picking someone to interrupt
  // right now, so reachability is the useful sort.
  const sorted = useMemo(() => {
    const rank = (id: string) => {
      const status = presence[id]?.status ?? "offline";
      return status === "active" ? 0 : status === "away" ? 1 : 2;
    };
    const needle = query.trim().toLowerCase();
    return members
      .filter(
        (row) =>
          !needle ||
          row.user.name.toLowerCase().includes(needle) ||
          row.user.email.toLowerCase().includes(needle),
      )
      .slice()
      .sort((a, b) => {
        const byPresence = rank(String(a.user.id)) - rank(String(b.user.id));
        return byPresence !== 0 ? byPresence : a.user.name.localeCompare(b.user.name);
      });
  }, [members, presence, query]);

  // The cap counts you as well, so the picker allows one fewer than the call's
  // limit — the server enforces the same arithmetic (see startCall).
  const maxInvitees = MAX_CALL_PARTICIPANTS - 1;
  const atCap = selected.length >= maxInvitees;

  function toggle(id: string) {
    setSelected((current) =>
      current.includes(id) ? current.filter((existing) => existing !== id) : atCap ? current : [...current, id],
    );
  }

  return (
    <div className="channel-invite-backdrop" role="presentation" onClick={onClose}>
      <div
        className="task-modal call-modal"
        role="dialog"
        aria-modal="true"
        aria-labelledby="new-call-title"
        onClick={(e) => e.stopPropagation()}
      >
        <div className="channel-invite-head">
          <div>
            <h2 id="new-call-title">New call</h2>
            <p>
              Ring up to {maxInvitees} {maxInvitees === 1 ? "person" : "people"} at once. They&apos;ll get a ring
              wherever they have the app open.
            </p>
          </div>
          <button className="thread-close" type="button" onClick={onClose} aria-label="Close">
            <IconX />
          </button>
        </div>

        <div className="task-modal-body">
          <div className="call-modal-kind" role="radiogroup" aria-label="Call type">
            <button
              type="button"
              role="radio"
              aria-checked={kind === "audio"}
              className={kind === "audio" ? "call-modal-kind-btn active" : "call-modal-kind-btn"}
              onClick={() => setKind("audio")}
            >
              <IconPhone size={15} />
              Audio
            </button>
            <button
              type="button"
              role="radio"
              aria-checked={kind === "video"}
              className={kind === "video" ? "call-modal-kind-btn active" : "call-modal-kind-btn"}
              onClick={() => setKind("video")}
            >
              <IconVideo size={15} />
              Video
            </button>
          </div>

          <div className="task-modal-field">
            <label htmlFor="new-call-topic">Topic (optional)</label>
            <input
              id="new-call-topic"
              type="text"
              value={title}
              maxLength={200}
              onChange={(e) => setTitle(e.target.value)}
              placeholder="What's this about?"
            />
          </div>

          <div className="task-modal-field">
            <label htmlFor="new-call-search">
              Who to call{selected.length > 0 && ` · ${selected.length} selected`}
            </label>
            <input
              id="new-call-search"
              type="search"
              value={query}
              autoFocus
              onChange={(e) => setQuery(e.target.value)}
              placeholder="Search people"
            />
          </div>

          <div className="task-modal-assignees">
            {sorted.map((row) => {
              const id = String(row.user.id);
              const isSelected = selected.includes(id);
              const color = avatarColor(id);
              const status = presence[id]?.status ?? "offline";
              return (
                <button
                  key={id}
                  type="button"
                  className={isSelected ? "channel-invite-row selected" : "channel-invite-row"}
                  // Not disabled outright at the cap: an already-selected row
                  // must stay clickable so the choice can be undone.
                  disabled={atCap && !isSelected}
                  onClick={() => toggle(id)}
                >
                  <span className="list-row-avatar" style={{ background: color.bg, color: color.fg }}>
                    {initials(row.user.name)}
                  </span>
                  <span className="channel-invite-meta">
                    <strong>{row.user.name}</strong>
                    <span>{PRESENCE_LABEL[status] ?? "Offline"}</span>
                  </span>
                  <span className="channel-invite-check" aria-hidden="true">
                    {isSelected ? "✓" : ""}
                  </span>
                </button>
              );
            })}
            {sorted.length === 0 && <div className="sidebar-empty">Nobody matches that.</div>}
          </div>

          {atCap && <p className="calls-hint">That&apos;s the most a mesh call can carry.</p>}
          {error && <p className="error-text">{error}</p>}
        </div>

        <div className="channel-invite-foot">
          <button className="screen-btn" type="button" onClick={onClose}>
            Cancel
          </button>
          <button
            className="screen-btn primary"
            type="button"
            disabled={busy || selected.length === 0}
            onClick={() => onSubmit({ userIds: selected, kind, title: title.trim() })}
          >
            {busy ? "Calling…" : kind === "video" ? "Start video call" : "Start call"}
          </button>
        </div>
      </div>
    </div>
  );
}
