import type { Component } from "solid-js";
import { Show, createMemo, createEffect, onCleanup } from "solid-js";
import { Portal } from "solid-js/web";
import { UserPlus, UserMinus, Copy, Check } from "lucide-solid";
import { createSignal } from "solid-js";
import Avatar from "./Avatar";
import {
  profileCardTarget,
  closeProfileCard,
  openProfileModal,
} from "../../stores/ui";
import { members, isPeerOnline } from "../../stores/members";
import { knownPeers } from "../../stores/directory";
import { identity } from "../../stores/identity";
import { settings } from "../../stores/settings";
import { markAsFriend, unmarkAsFriend } from "../../stores/directory";
import * as tauri from "../../lib/tauri";
import { formatTime } from "../../lib/utils";

const ProfileCard: Component = () => {
  const [copied, setCopied] = createSignal(false);
  let cardRef: HTMLDivElement | undefined;

  const target = () => profileCardTarget();
  const isOpen = () => target() !== null;
  const isSelf = () => target()?.peerId === identity()?.peer_id;

  // pull rich info from member list or directory
  const memberInfo = createMemo(() => {
    const t = target();
    if (!t) return null;
    return members().find((m) => m.peer_id === t.peerId) ?? null;
  });

  const directoryInfo = createMemo(() => {
    const t = target();
    if (!t) return null;
    return knownPeers().find((p) => p.peer_id === t.peerId) ?? null;
  });

  const displayName = () =>
    memberInfo()?.display_name ??
    directoryInfo()?.display_name ??
    target()?.displayName ??
    (isSelf() ? identity()?.display_name : null) ??
    "Unknown";

  const bio = () =>
    directoryInfo()?.bio || (isSelf() ? identity()?.bio : "") || "";
  const isFriend = () => directoryInfo()?.is_friend ?? false;
  // local user always knows their own status from settings;
  // remote peers use member list status or online tracking as fallback
  const status = () => {
    if (isSelf()) {
      const s = settings().status;
      if (s === "invisible") return "Offline";
      return (s.charAt(0).toUpperCase() + s.slice(1)) as
        | "Online"
        | "Idle"
        | "Dnd"
        | "Offline";
    }
    const member = memberInfo();
    if (member) return member.status;
    const t = target();
    if (t && isPeerOnline(t.peerId)) return "Online";
    return "Offline";
  };
  const roles = () => memberInfo()?.roles ?? [];
  const joinedAt = () => memberInfo()?.joined_at ?? 0;

  // close on escape or click outside
  function handleKeydown(e: KeyboardEvent) {
    if (e.key === "Escape") closeProfileCard();
  }

  function handleClickOutside(e: MouseEvent) {
    if (cardRef && !cardRef.contains(e.target as Node)) {
      closeProfileCard();
    }
  }

  createEffect(() => {
    if (isOpen()) {
      // delay listener registration to avoid the triggering click from closing it
      requestAnimationFrame(() => {
        document.addEventListener("mousedown", handleClickOutside);
      });
      document.addEventListener("keydown", handleKeydown);
    }
  });

  onCleanup(() => {
    document.removeEventListener("mousedown", handleClickOutside);
    document.removeEventListener("keydown", handleKeydown);
  });

  // close and re-register listeners whenever the target changes
  createEffect(() => {
    if (!isOpen()) {
      document.removeEventListener("mousedown", handleClickOutside);
      document.removeEventListener("keydown", handleKeydown);
    }
  });

  // compute position to stay within viewport
  const cardPosition = createMemo(() => {
    const t = target();
    if (!t) return { top: 0, left: 0 };

    const cardWidth = 320;
    const cardHeight = 340;
    const margin = 12;
    const vw = window.innerWidth;
    const vh = window.innerHeight;

    let left = t.anchorX + margin;
    let top = t.anchorY - cardHeight / 3;

    // flip horizontally if overflowing right
    if (left + cardWidth > vw - margin) {
      left = t.anchorX - cardWidth - margin;
    }

    // clamp vertically
    if (top < margin) top = margin;
    if (top + cardHeight > vh - margin) top = vh - cardHeight - margin;

    return { top, left };
  });

  async function handleToggleFriend() {
    const t = target();
    if (!t) return;

    try {
      if (isFriend()) {
        await tauri.removeFriend(t.peerId);
        unmarkAsFriend(t.peerId);
      } else {
        await tauri.addFriend(t.peerId);
        markAsFriend(t.peerId);
      }
    } catch (e) {
      console.error("failed to toggle friend:", e);
    }
  }

  async function handleCopyPeerId() {
    const t = target();
    if (!t) return;

    try {
      await navigator.clipboard.writeText(t.peerId);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch {
      // clipboard api may fail outside secure contexts
    }
  }

  function handleOpenFullProfile() {
    const t = target();
    if (t) openProfileModal(t.peerId);
  }

  const statusLabel = () => {
    const s = status();
    if (s === "Online") return "online";
    if (s === "Idle") return "idle";
    return "offline";
  };

  const statusColor = () => {
    const s = status();
    if (s === "Online") return "bg-success";
    if (s === "Idle") return "bg-warning";
    return "bg-gray-300";
  };

  return (
    <Show when={isOpen()}>
      <Portal>
        <div
          ref={cardRef}
          class="fixed z-2000 w-[320px] bg-gray-900 border border-white/20 animate-scale-in overflow-hidden"
          style={{
            top: `${cardPosition().top}px`,
            left: `${cardPosition().left}px`,
          }}
        >
          {/* header banner */}
          <div class="h-16 bg-linear-to-r from-orange/30 to-orange/10" />

          {/* avatar overlapping the banner */}
          <div class="px-4 -mt-8">
            <button
              type="button"
              class="cursor-pointer"
              onClick={handleOpenFullProfile}
            >
              <Avatar
                name={displayName()}
                size="xl"
                status={status()}
                showStatus
              />
            </button>
          </div>

          {/* user info */}
          <div class="px-4 pt-2 pb-3">
            <div class="flex items-center gap-2">
              <button
                type="button"
                class="text-[18px] font-semibold text-white truncate hover:text-orange transition-colors duration-200 cursor-pointer"
                onClick={handleOpenFullProfile}
              >
                {displayName()}
              </button>
              <Show when={isSelf()}>
                <span class="text-[11px] font-mono text-white/40 shrink-0">
                  (you)
                </span>
              </Show>
            </div>

            {/* status indicator */}
            <div class="flex items-center gap-1.5 mt-1">
              <div class={`w-2 h-2 rounded-full ${statusColor()}`} />
              <span class="text-[12px] font-mono text-white/50">
                {statusLabel()}
              </span>
            </div>

            {/* bio */}
            <Show when={bio()}>
              <p class="text-[13px] text-white/70 mt-2 leading-relaxed line-clamp-3">
                {bio()}
              </p>
            </Show>
          </div>

          {/* metadata section */}
          <div class="border-t border-white/10 mx-4" />

          <div class="px-4 py-3 space-y-2">
            {/* roles */}
            <Show when={roles().length > 0}>
              <div>
                <span class="text-[11px] font-mono uppercase tracking-[0.05em] text-white/40">
                  roles
                </span>
                <div class="flex flex-wrap gap-1.5 mt-1">
                  {roles().map((role) => (
                    <span class="text-[11px] font-mono px-2 py-0.5 bg-orange/15 text-orange border border-orange/30">
                      {role}
                    </span>
                  ))}
                </div>
              </div>
            </Show>

            {/* joined date */}
            <Show when={joinedAt() > 0}>
              <div>
                <span class="text-[11px] font-mono uppercase tracking-[0.05em] text-white/40">
                  member since
                </span>
                <p class="text-[12px] font-mono text-white/60 mt-0.5">
                  {formatTime(joinedAt())}
                </p>
              </div>
            </Show>

            {/* peer id */}
            <div>
              <span class="text-[11px] font-mono uppercase tracking-[0.05em] text-white/40">
                peer id
              </span>
              <button
                type="button"
                class="flex items-center gap-1.5 mt-0.5 group cursor-pointer"
                onClick={handleCopyPeerId}
              >
                <span class="text-[11px] font-mono text-white/40 group-hover:text-white/60 transition-colors duration-200 truncate max-w-55">
                  {target()?.peerId}
                </span>
                <Show
                  when={copied()}
                  fallback={
                    <Copy
                      size={12}
                      class="shrink-0 text-white/30 group-hover:text-white/50 transition-colors duration-200"
                    />
                  }
                >
                  <Check size={12} class="shrink-0 text-success" />
                </Show>
              </button>
            </div>
          </div>

          {/* action buttons */}
          <Show when={!isSelf()}>
            <div class="border-t border-white/10 mx-4" />
            <div class="px-4 py-3 flex gap-2">
              <button
                type="button"
                class={`flex items-center gap-1.5 px-3 py-1.5 text-[12px] font-medium transition-colors duration-200 cursor-pointer ${
                  isFriend()
                    ? "text-red-400 border border-red-400/30 hover:bg-red-400/10"
                    : "text-orange border border-orange/30 hover:bg-orange/10"
                }`}
                onClick={handleToggleFriend}
              >
                <Show
                  when={isFriend()}
                  fallback={
                    <>
                      <UserPlus size={14} />
                      add friend
                    </>
                  }
                >
                  <UserMinus size={14} />
                  remove friend
                </Show>
              </button>
            </div>
          </Show>
        </div>
      </Portal>
    </Show>
  );
};

export default ProfileCard;
