/**
 * <rstack-module-comments> — Spatial comment pins on rApp module pages.
 *
 * Anchors Figma-style threaded comment markers to `data-collab-id` elements.
 * Stores pins in a per-space Automerge doc: `{space}:module-comments:pins`.
 *
 * Attributes: `module-id`, `space` (both set by shell).
 *
 * Events emitted:
 *   - `module-comment-pins-changed` on window when doc changes
 *
 * Events consumed:
 *   - `comment-pin-activate` on window → enter placement mode
 *   - `module-comment-pin-focus` on window → scroll to + highlight a pin
 */

import { moduleCommentsSchema, moduleCommentsDocId } from '../module-comment-schemas';
import type { ModuleCommentPin, ModuleCommentsDoc } from '../module-comment-types';
import type { CommentPinMessage } from '../comment-pin-types';
import type { DocumentId } from '../local-first/document';
import { getModuleApiBase } from '../url-helpers';

interface SpaceMember {
  userDID: string;
  username: string;
  displayName?: string;
}

type OfflineRuntime = {
  isInitialized: boolean;
  subscribe<T extends Record<string, any>>(docId: DocumentId, schema: any): Promise<any>;
  unsubscribe(docId: DocumentId): void;
  change<T>(docId: DocumentId, message: string, fn: (doc: T) => void): void;
  get<T>(docId: DocumentId): any;
  onChange<T>(docId: DocumentId, cb: (doc: any) => void): () => void;
};

export class RStackModuleComments extends HTMLElement {
  #moduleId = '';
  #space = '';
  #docId: DocumentId | null = null;
  #runtime: OfflineRuntime | null = null;
  #unsubChange: (() => void) | null = null;
  #overlay: HTMLDivElement | null = null;
  #popover: HTMLDivElement | null = null;
  #placementMode = false;
  #activePinId: string | null = null;
  #members: SpaceMember[] | null = null;
  #mentionDropdown: HTMLDivElement | null = null;

  // Observers
  #resizeObs: ResizeObserver | null = null;
  #mutationObs: MutationObserver | null = null;
  #intersectionObs: IntersectionObserver | null = null;
  #scrollHandler: (() => void) | null = null;
  #repositionTimer: ReturnType<typeof setTimeout> | null = null;
  #runtimePollInterval: ReturnType<typeof setInterval> | null = null;

  connectedCallback() {
    this.#moduleId = this.getAttribute('module-id') || '';
    this.#space = this.getAttribute('space') || '';

    if (!this.#moduleId || !this.#space || this.#moduleId === 'rspace') return;

    this.#docId = moduleCommentsDocId(this.#space);

    // Create overlay layer
    this.#overlay = document.createElement('div');
    this.#overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9998;';
    document.body.appendChild(this.#overlay);

    // Create popover container
    this.#popover = document.createElement('div');
    this.#popover.style.cssText = `
      display:none;position:fixed;z-index:10001;width:340px;max-height:400px;
      background:#1e1e2e;border:1px solid #444;border-radius:10px;
      box-shadow:0 8px 30px rgba(0,0,0,0.4);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
      color:#e0e0e0;font-size:13px;overflow:hidden;pointer-events:auto;
    `;
    document.body.appendChild(this.#popover);

    // Try connecting to runtime
    this.#tryConnect();

    // Listen for events
    window.addEventListener('comment-pin-activate', this.#onActivate);
    window.addEventListener('module-comment-pin-focus', this.#onPinFocus as EventListener);
    document.addEventListener('pointerdown', this.#onDocumentClick);
  }

  disconnectedCallback() {
    if (this.#unsubChange) this.#unsubChange();
    if (this.#runtimePollInterval) clearInterval(this.#runtimePollInterval);
    if (this.#resizeObs) this.#resizeObs.disconnect();
    if (this.#mutationObs) this.#mutationObs.disconnect();
    if (this.#intersectionObs) this.#intersectionObs.disconnect();
    if (this.#scrollHandler) window.removeEventListener('scroll', this.#scrollHandler, true);
    if (this.#repositionTimer) clearTimeout(this.#repositionTimer);
    if (this.#overlay) this.#overlay.remove();
    if (this.#popover) this.#popover.remove();
    window.removeEventListener('comment-pin-activate', this.#onActivate);
    window.removeEventListener('module-comment-pin-focus', this.#onPinFocus as EventListener);
    document.removeEventListener('pointerdown', this.#onDocumentClick);
    this.#exitPlacementMode();
  }

  // ── Runtime Connection ──

  #tryConnect() {
    const runtime = (window as any).__rspaceOfflineRuntime as OfflineRuntime | undefined;
    if (runtime?.isInitialized) {
      this.#onRuntimeReady(runtime);
    } else {
      let polls = 0;
      this.#runtimePollInterval = setInterval(() => {
        const rt = (window as any).__rspaceOfflineRuntime as OfflineRuntime | undefined;
        if (rt?.isInitialized) {
          clearInterval(this.#runtimePollInterval!);
          this.#runtimePollInterval = null;
          this.#onRuntimeReady(rt);
        } else if (++polls > 20) {
          clearInterval(this.#runtimePollInterval!);
          this.#runtimePollInterval = null;
        }
      }, 500);
    }
  }

  async #onRuntimeReady(runtime: OfflineRuntime) {
    this.#runtime = runtime;
    if (!this.#docId) return;

    await runtime.subscribe<ModuleCommentsDoc>(this.#docId, moduleCommentsSchema);

    this.#unsubChange = runtime.onChange<ModuleCommentsDoc>(this.#docId, () => {
      this.#renderPins();
      window.dispatchEvent(new CustomEvent('module-comment-pins-changed'));
    });

    // Set up observers for repositioning
    this.#setupObservers();
    this.#renderPins();
  }

  // ── Observers ──

  #setupObservers() {
    // Debounced reposition
    const debouncedReposition = () => {
      if (this.#repositionTimer) clearTimeout(this.#repositionTimer);
      this.#repositionTimer = setTimeout(() => this.#renderPins(), 100);
    };

    // Scroll (capture phase for inner scrollable elements)
    this.#scrollHandler = debouncedReposition;
    window.addEventListener('scroll', this.#scrollHandler, true);

    // Resize
    this.#resizeObs = new ResizeObserver(debouncedReposition);
    this.#resizeObs.observe(document.body);

    // DOM mutations (elements added/removed)
    this.#mutationObs = new MutationObserver(debouncedReposition);
    this.#mutationObs.observe(document.body, { childList: true, subtree: true });
  }

  // ── Pin Rendering ──

  #getDoc(): ModuleCommentsDoc | undefined {
    if (!this.#runtime || !this.#docId) return undefined;
    return this.#runtime.get<ModuleCommentsDoc>(this.#docId);
  }

  #getPinsForModule(): [string, ModuleCommentPin][] {
    const doc = this.#getDoc();
    if (!doc?.pins) return [];
    return Object.entries(doc.pins).filter(
      ([, pin]) => pin.anchor.moduleId === this.#moduleId
    );
  }

  #findCollabEl(id: string): Element | null {
    const sel = `[data-collab-id="${CSS.escape(id)}"]`;
    const found = document.querySelector(sel);
    if (found) return found;
    // Walk into shadow roots (one level deep — rApp components)
    for (const el of document.querySelectorAll('*')) {
      if (el.shadowRoot) {
        const inner = el.shadowRoot.querySelector(sel);
        if (inner) return inner;
      }
    }
    return null;
  }

  #renderPins() {
    if (!this.#overlay) return;
    const pins = this.#getPinsForModule();

    // Clear existing markers
    this.#overlay.innerHTML = '';

    for (const [pinId, pin] of pins) {
      const el = this.#findCollabEl(pin.anchor.elementId);
      if (!el) continue;

      const rect = el.getBoundingClientRect();
      // Skip if off-screen
      if (rect.bottom < 0 || rect.top > window.innerHeight ||
          rect.right < 0 || rect.left > window.innerWidth) continue;

      const marker = document.createElement('div');
      marker.dataset.pinId = pinId;
      const isActive = this.#activePinId === pinId;
      const isResolved = pin.resolved;
      const msgCount = pin.messages?.length || 0;

      marker.style.cssText = `
        position:fixed;
        left:${rect.right - 12}px;
        top:${rect.top - 8}px;
        width:24px;height:24px;
        border-radius:50% 50% 50% 0;
        transform:rotate(-45deg);
        cursor:pointer;
        pointer-events:auto;
        display:flex;align-items:center;justify-content:center;
        font-size:10px;font-weight:700;color:white;
        transition:all 0.15s ease;
        box-shadow:0 2px 8px rgba(0,0,0,0.3);
        ${isResolved
          ? 'background:#64748b;opacity:0.6;'
          : isActive
            ? 'background:#8b5cf6;transform:rotate(-45deg) scale(1.15);'
            : 'background:#14b8a6;'}
      `;

      // Badge with message count
      if (msgCount > 0) {
        const badge = document.createElement('span');
        badge.textContent = String(msgCount);
        badge.style.cssText = 'transform:rotate(45deg);';
        marker.appendChild(badge);
      }

      marker.addEventListener('click', (e) => {
        e.stopPropagation();
        this.#openPopover(pinId, rect.right + 8, rect.top);
      });

      this.#overlay.appendChild(marker);
    }
  }

  // ── Placement Mode ──

  #onActivate = () => {
    // Only handle if we're on a module page (not canvas)
    if (this.#moduleId === 'rspace' || !this.#runtime) return;
    if (this.#placementMode) {
      this.#exitPlacementMode();
    } else {
      this.#enterPlacementMode();
    }
  };

  #enterPlacementMode() {
    this.#placementMode = true;
    document.body.style.cursor = 'crosshair';

    // Highlight valid targets
    this.#highlightCollabElements(true);
  }

  #exitPlacementMode() {
    this.#placementMode = false;
    document.body.style.cursor = '';
    this.#highlightCollabElements(false);
  }

  #highlightCollabElements(show: boolean) {
    const els = document.querySelectorAll('[data-collab-id]');
    els.forEach((el) => {
      (el as HTMLElement).style.outline = show ? '2px dashed rgba(20,184,166,0.4)' : '';
      (el as HTMLElement).style.outlineOffset = show ? '2px' : '';
    });
    // Also check shadow roots
    for (const el of document.querySelectorAll('*')) {
      if (el.shadowRoot) {
        el.shadowRoot.querySelectorAll('[data-collab-id]').forEach((inner) => {
          (inner as HTMLElement).style.outline = show ? '2px dashed rgba(20,184,166,0.4)' : '';
          (inner as HTMLElement).style.outlineOffset = show ? '2px' : '';
        });
      }
    }
  }

  #onDocumentClick = (e: PointerEvent) => {
    if (!this.#placementMode) {
      // Close popover on outside click
      if (this.#popover?.style.display !== 'none' &&
          !this.#popover?.contains(e.target as Node) &&
          !(e.target as HTMLElement)?.closest?.('[data-pin-id]')) {
        this.#closePopover();
      }
      return;
    }

    const target = (e.target as HTMLElement).closest('[data-collab-id]');
    if (!target) return; // Ignore clicks not on collab elements

    e.preventDefault();
    e.stopPropagation();

    const elementId = target.getAttribute('data-collab-id')!;
    this.#exitPlacementMode();
    this.#createPin(elementId);
  };

  // ── CRDT Operations ──

  #getUserInfo(): { did: string; name: string } {
    try {
      const sess = JSON.parse(localStorage.getItem('encryptid_session') || '{}');
      return {
        did: sess.did || 'anon',
        name: sess.username || sess.displayName || 'Anonymous',
      };
    } catch {
      return { did: 'anon', name: 'Anonymous' };
    }
  }

  #createPin(elementId: string) {
    if (!this.#runtime || !this.#docId) return;
    const user = this.#getUserInfo();
    const pinId = crypto.randomUUID();

    this.#runtime.change<ModuleCommentsDoc>(this.#docId, 'Add module comment pin', (doc) => {
      doc.pins[pinId] = {
        id: pinId,
        anchor: { type: 'element', elementId, moduleId: this.#moduleId },
        resolved: false,
        messages: [],
        createdAt: Date.now(),
        createdBy: user.did,
        createdByName: user.name,
      };
    });

    // Open popover immediately for the new pin
    requestAnimationFrame(() => {
      const el = this.#findCollabEl(elementId);
      if (el) {
        const rect = el.getBoundingClientRect();
        this.#openPopover(pinId, rect.right + 8, rect.top, true);
      }
    });
  }

  #addMessage(pinId: string, text: string) {
    if (!this.#runtime || !this.#docId) return;
    const user = this.#getUserInfo();
    const msgId = crypto.randomUUID();

    // Extract @mentions
    const mentionedDids = this.#extractMentions(text);

    this.#runtime.change<ModuleCommentsDoc>(this.#docId, 'Add comment', (doc) => {
      const pin = doc.pins[pinId];
      if (!pin) return;
      pin.messages.push({
        id: msgId,
        authorId: user.did,
        authorName: user.name,
        text,
        mentionedDids: mentionedDids.length > 0 ? mentionedDids : undefined,
        createdAt: Date.now(),
      });
    });

    // Notify space members
    this.#notifySpaceMembers(pinId, text, user, mentionedDids);

    // Notify @mentioned users
    if (mentionedDids.length > 0) {
      this.#notifyMentions(pinId, user, mentionedDids);
    }
  }

  #resolvePin(pinId: string) {
    if (!this.#runtime || !this.#docId) return;
    this.#runtime.change<ModuleCommentsDoc>(this.#docId, 'Resolve pin', (doc) => {
      const pin = doc.pins[pinId];
      if (pin) pin.resolved = true;
    });
    this.#closePopover();
  }

  #unresolvePin(pinId: string) {
    if (!this.#runtime || !this.#docId) return;
    this.#runtime.change<ModuleCommentsDoc>(this.#docId, 'Unresolve pin', (doc) => {
      const pin = doc.pins[pinId];
      if (pin) pin.resolved = false;
    });
  }

  #deletePin(pinId: string) {
    if (!this.#runtime || !this.#docId) return;
    this.#runtime.change<ModuleCommentsDoc>(this.#docId, 'Delete pin', (doc) => {
      delete doc.pins[pinId];
    });
    this.#closePopover();
  }

  // ── Notifications ──

  async #notifySpaceMembers(pinId: string, text: string, user: { did: string; name: string }, mentionedDids: string[]) {
    const doc = this.#getDoc();
    if (!doc?.pins[pinId]) return;
    const pin = doc.pins[pinId];
    const isReply = pin.messages.length > 1;
    const pinIndex = Object.values(doc.pins)
      .sort((a, b) => a.createdAt - b.createdAt)
      .findIndex((p) => p.id === pinId) + 1;

    try {
      const base = getModuleApiBase('rspace');
      await fetch(`${base}/api/comment-pins/notify`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          pinId, authorDid: user.did, authorName: user.name,
          text, pinIndex, isReply, mentionedDids,
          moduleId: this.#moduleId,
        }),
      });
    } catch { /* fire and forget */ }
  }

  async #notifyMentions(pinId: string, user: { did: string; name: string }, mentionedDids: string[]) {
    const doc = this.#getDoc();
    if (!doc?.pins[pinId]) return;
    const pinIndex = Object.values(doc.pins)
      .sort((a, b) => a.createdAt - b.createdAt)
      .findIndex((p) => p.id === pinId) + 1;

    try {
      const base = getModuleApiBase('rspace');
      await fetch(`${base}/api/comment-pins/notify-mention`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          pinId, authorDid: user.did, authorName: user.name,
          mentionedDids, pinIndex, moduleId: this.#moduleId,
        }),
      });
    } catch { /* fire and forget */ }
  }

  #extractMentions(text: string): string[] {
    if (!this.#members) return [];
    const matches = text.match(/@(\w+)/g);
    if (!matches) return [];
    const dids: string[] = [];
    for (const match of matches) {
      const username = match.slice(1).toLowerCase();
      const member = this.#members.find(
        (m) => m.username.toLowerCase() === username
      );
      if (member) dids.push(member.userDID);
    }
    return dids;
  }

  // ── Popover ──

  #openPopover(pinId: string, x: number, y: number, focusInput = false) {
    if (!this.#popover) return;
    this.#activePinId = pinId;
    const doc = this.#getDoc();
    const pin = doc?.pins[pinId];
    if (!pin) return;

    const sortedPins = Object.values(doc!.pins).sort((a, b) => a.createdAt - b.createdAt);
    const pinIndex = sortedPins.findIndex((p) => p.id === pinId) + 1;

    let html = `<style>${POPOVER_STYLES}</style>`;

    // Header
    html += `
      <div class="mcp-header">
        <span class="mcp-pin-num">Pin #${pinIndex}</span>
        <div class="mcp-actions">
          ${pin.resolved
            ? `<button class="mcp-btn" data-action="unresolve" title="Reopen">&#x21A9;</button>`
            : `<button class="mcp-btn" data-action="resolve" title="Resolve">&#x2713;</button>`}
          <button class="mcp-btn mcp-btn-danger" data-action="delete" title="Delete">&#x2715;</button>
        </div>
      </div>
    `;

    // Element anchor label
    html += `<div class="mcp-anchor-label">${this.#esc(pin.anchor.elementId)}</div>`;

    // Messages
    if (pin.messages.length > 0) {
      html += `<div class="mcp-messages">`;
      for (const msg of pin.messages) {
        const time = new Date(msg.createdAt).toLocaleString(undefined, {
          month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit',
        });
        html += `
          <div class="mcp-msg">
            <div class="mcp-msg-top">
              <span class="mcp-msg-author">${this.#esc(msg.authorName)}</span>
              <span class="mcp-msg-time">${time}</span>
            </div>
            <div class="mcp-msg-text">${this.#formatText(msg.text)}</div>
          </div>
        `;
      }
      html += `</div>`;
    }

    // Input row
    html += `
      <div class="mcp-input-row">
        <input type="text" class="mcp-input" placeholder="Add a comment... (@ to mention)" />
        <button class="mcp-send">Send</button>
      </div>
    `;

    this.#popover.innerHTML = html;
    this.#popover.style.display = 'block';

    // Position — keep within viewport
    const popW = 340, popH = 400;
    const clampedX = Math.min(x, window.innerWidth - popW - 8);
    const clampedY = Math.min(Math.max(y, 8), window.innerHeight - popH - 8);
    this.#popover.style.left = `${clampedX}px`;
    this.#popover.style.top = `${clampedY}px`;

    // Wire actions
    this.#popover.querySelectorAll('.mcp-btn').forEach((btn) => {
      btn.addEventListener('click', (e) => {
        const action = (e.currentTarget as HTMLElement).dataset.action;
        if (action === 'resolve') this.#resolvePin(pinId);
        else if (action === 'unresolve') this.#unresolvePin(pinId);
        else if (action === 'delete') this.#deletePin(pinId);
      });
    });

    // Wire input
    const input = this.#popover.querySelector('.mcp-input') as HTMLInputElement;
    const sendBtn = this.#popover.querySelector('.mcp-send') as HTMLButtonElement;

    const submitComment = () => {
      const text = input.value.trim();
      if (!text) return;
      this.#addMessage(pinId, text);
      input.value = '';
      // Re-render popover to show new message
      requestAnimationFrame(() => {
        const el = this.#findCollabEl(pin.anchor.elementId);
        if (el) {
          const rect = el.getBoundingClientRect();
          this.#openPopover(pinId, rect.right + 8, rect.top);
        }
      });
    };

    sendBtn.addEventListener('click', submitComment);
    input.addEventListener('keydown', (e) => {
      if (e.key === 'Enter' && !e.shiftKey) {
        e.preventDefault();
        submitComment();
      }
      if (e.key === 'Escape') this.#closePopover();
    });

    // @mention autocomplete
    input.addEventListener('input', () => this.#handleMentionInput(input));

    // Prevent popover clicks from closing it
    this.#popover.addEventListener('pointerdown', (e) => e.stopPropagation());

    if (focusInput) {
      requestAnimationFrame(() => input.focus());
    }

    this.#renderPins(); // Update active state on markers
  }

  #closePopover() {
    if (this.#popover) this.#popover.style.display = 'none';
    this.#activePinId = null;
    this.#closeMentionDropdown();
    this.#renderPins();
  }

  // ── Pin Focus (from bell) ──

  #onPinFocus = (e: CustomEvent) => {
    const { pinId, elementId } = e.detail || {};
    if (!pinId) return;

    const doc = this.#getDoc();
    const pin = doc?.pins[pinId];
    if (!pin || pin.anchor.moduleId !== this.#moduleId) return;

    const el = this.#findCollabEl(pin.anchor.elementId || elementId);
    if (el) {
      el.scrollIntoView({ behavior: 'smooth', block: 'center' });
      requestAnimationFrame(() => {
        const rect = el.getBoundingClientRect();
        this.#openPopover(pinId, rect.right + 8, rect.top);
      });
    }
  };

  // ── @Mention Autocomplete ──

  async #fetchMembers() {
    if (this.#members) return this.#members;
    try {
      const sess = JSON.parse(localStorage.getItem('encryptid_session') || '{}');
      const res = await fetch(`${getModuleApiBase('rspace')}/api/space-members`, {
        headers: sess?.accessToken ? { Authorization: `Bearer ${sess.accessToken}` } : {},
      });
      if (!res.ok) return [];
      const data = await res.json();
      this.#members = data.members || [];
      return this.#members!;
    } catch {
      return [];
    }
  }

  async #handleMentionInput(input: HTMLInputElement) {
    const val = input.value;
    const cursorPos = input.selectionStart || 0;
    const before = val.slice(0, cursorPos);
    const atMatch = before.match(/@(\w*)$/);

    if (!atMatch) {
      this.#closeMentionDropdown();
      return;
    }

    const query = atMatch[1].toLowerCase();
    const members = await this.#fetchMembers();
    const filtered = members.filter(
      (m) =>
        m.username.toLowerCase().includes(query) ||
        (m.displayName && m.displayName.toLowerCase().includes(query)),
    );

    if (filtered.length === 0) {
      this.#closeMentionDropdown();
      return;
    }

    this.#showMentionDropdown(filtered, input, atMatch.index!);
  }

  #showMentionDropdown(members: SpaceMember[], input: HTMLInputElement, atIndex: number) {
    this.#closeMentionDropdown();

    const dropdown = document.createElement('div');
    dropdown.style.cssText = `
      position:absolute;bottom:100%;left:12px;right:12px;
      background:#2a2a3a;border:1px solid #555;border-radius:6px;
      max-height:150px;overflow-y:auto;z-index:10002;
    `;

    for (const m of members.slice(0, 8)) {
      const item = document.createElement('div');
      item.style.cssText = 'padding:6px 10px;cursor:pointer;font-size:12px;display:flex;justify-content:space-between;';
      item.innerHTML = `
        <span style="font-weight:600;">${this.#esc(m.displayName || m.username)}</span>
        <span style="color:#888;">@${this.#esc(m.username)}</span>
      `;
      item.addEventListener('mousedown', (e) => {
        e.preventDefault();
        const val = input.value;
        const before = val.slice(0, atIndex);
        const after = val.slice(input.selectionStart || atIndex);
        input.value = `${before}@${m.username} ${after}`;
        input.focus();
        const newPos = atIndex + m.username.length + 2;
        input.setSelectionRange(newPos, newPos);
        this.#closeMentionDropdown();
      });
      item.addEventListener('mouseenter', () => { item.style.background = '#3a3a4a'; });
      item.addEventListener('mouseleave', () => { item.style.background = ''; });
      dropdown.appendChild(item);
    }

    const inputRow = this.#popover?.querySelector('.mcp-input-row');
    if (inputRow) {
      (inputRow as HTMLElement).style.position = 'relative';
      inputRow.appendChild(dropdown);
    }
    this.#mentionDropdown = dropdown;
  }

  #closeMentionDropdown() {
    if (this.#mentionDropdown) {
      this.#mentionDropdown.remove();
      this.#mentionDropdown = null;
    }
  }

  // ── Helpers ──

  #esc(s: string): string {
    return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
  }

  #formatText(text: string): string {
    // Escape first, then render @mentions with highlight
    let escaped = this.#esc(text);
    escaped = escaped.replace(/@(\w+)/g, '<span style="color:#14b8a6;font-weight:600;">@$1</span>');
    return escaped;
  }

  static define(tag = 'rstack-module-comments') {
    if (!customElements.get(tag)) customElements.define(tag, RStackModuleComments);
  }
}

// ── Popover Styles ──

const POPOVER_STYLES = `
.mcp-header {
  padding: 10px 12px;
  border-bottom: 1px solid #333;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.mcp-pin-num {
  font-weight: 700;
  color: #14b8a6;
}
.mcp-actions {
  display: flex;
  gap: 4px;
}
.mcp-btn {
  background: none;
  border: 1px solid #444;
  border-radius: 4px;
  padding: 2px 6px;
  cursor: pointer;
  color: #ccc;
  font-size: 13px;
}
.mcp-btn:hover { background: #333; }
.mcp-btn-danger { color: #ef4444; }
.mcp-btn-danger:hover { background: #3a1a1a; }
.mcp-anchor-label {
  padding: 4px 12px;
  font-size: 11px;
  color: #64748b;
  border-bottom: 1px solid #333;
  background: rgba(255,255,255,0.02);
}
.mcp-messages {
  max-height: 200px;
  overflow-y: auto;
  padding: 8px 12px;
}
.mcp-msg {
  margin-bottom: 10px;
}
.mcp-msg-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.mcp-msg-author {
  font-weight: 600;
  color: #c4b5fd;
  font-size: 12px;
}
.mcp-msg-time {
  color: #666;
  font-size: 10px;
}
.mcp-msg-text {
  margin-top: 3px;
  line-height: 1.4;
  word-break: break-word;
}
.mcp-input-row {
  padding: 8px 12px;
  border-top: 1px solid #333;
  display: flex;
  gap: 6px;
}
.mcp-input {
  flex: 1;
  background: #2a2a3a;
  border: 1px solid #444;
  border-radius: 6px;
  padding: 6px 10px;
  color: #e0e0e0;
  font-size: 13px;
  outline: none;
}
.mcp-input:focus {
  border-color: #14b8a6;
}
.mcp-send {
  background: #14b8a6;
  color: white;
  border: none;
  border-radius: 6px;
  padding: 6px 12px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
}
.mcp-send:hover {
  background: #0d9488;
}
`;
