/**
 * FrontmatterPopupManager - Manages frontmatter popup display for agent skills
 * Extracted from AgentSkillManager to reduce file size and improve maintainability
 */

import { calculatePopupPosition, applyPopupPosition } from './utils/popup-position-calculator';
import { renderFrontmatter } from './utils/frontmatter-renderer';
import { UI_TIMING } from '../constants';

interface AgentSkillItemLike {
  name: string;
  filePath: string;
  tooltip?: string;
}

/**
 * Callbacks for FrontmatterPopupManager to interact with parent components
 */
export interface FrontmatterPopupCallbacks {
  getSuggestionsContainer: () => HTMLElement | null;
  getFilteredSkills: () => AgentSkillItemLike[];
  getSelectedIndex: () => number;
  onBeforeOpenFile?: () => void;
  setDraggable?: (value: boolean) => void;
  onSelectSkill?: (command: AgentSkillItemLike) => void;
}

/**
 * Manages frontmatter popup display for agent skill items
 */
export class FrontmatterPopupManager {
  private static readonly POPUP_HIDE_DELAY = UI_TIMING.POPUP_HIDE_DELAY; // ms delay before hiding popup

  private frontmatterPopup: HTMLElement | null = null;
  private popupHideTimeout: ReturnType<typeof setTimeout> | null = null;
  private isPopupVisible: boolean = false;
  private autoShowTooltip: boolean = false;
  private callbacks: FrontmatterPopupCallbacks;

  // Row hover tracking for tooltip persistence
  private currentRowElement: Element | null = null;
  private boundRowMouseEnter: (() => void) | null = null;
  private boundRowMouseLeave: (() => void) | null = null;

  constructor(callbacks: FrontmatterPopupCallbacks) {
    this.callbacks = callbacks;
  }

  /**
   * Create the frontmatter popup element for agent skill hover display
   */
  public createPopup(): void {
    if (this.frontmatterPopup) return;

    this.frontmatterPopup = document.createElement('div');
    this.frontmatterPopup.id = 'agentSkillFrontmatterPopup';
    this.frontmatterPopup.className = 'frontmatter-popup';
    this.frontmatterPopup.style.display = 'none';

    // Prevent popup from closing when hovering over it
    this.frontmatterPopup.addEventListener('mouseenter', () => {
      this.cancelHide();
    });

    this.frontmatterPopup.addEventListener('mouseleave', () => {
      this.scheduleHide();
    });

    // Handle wheel events on popup element only (scroll popup content)
    this.frontmatterPopup.addEventListener('wheel', (e) => {
      const popup = this.frontmatterPopup;
      if (popup) {
        const canScrollDown = popup.scrollTop < popup.scrollHeight - popup.clientHeight;
        const canScrollUp = popup.scrollTop > 0;
        if ((e.deltaY > 0 && canScrollDown) || (e.deltaY < 0 && canScrollUp)) {
          e.preventDefault();
          e.stopPropagation();
          popup.scrollTop += e.deltaY;
        }
      }
    }, { passive: false });

    // Append to main-content
    const mainContent = document.querySelector('.main-content');
    if (mainContent) {
      mainContent.appendChild(this.frontmatterPopup);
    }
  }

  /**
   * Add file path as frontmatter line to content container
   */
  private addFilePathLine(contentDiv: HTMLElement, command: AgentSkillItemLike): void {
    const filePath = command.filePath;
    if (!filePath || filePath.startsWith('command-source:')) return;

    try {
      // Replace home directory with ~ for display
      const displayPath = filePath.replace(/^\/Users\/[^/]+/, '~');

      // Create frontmatter line for file path
      const lineDiv = document.createElement('div');
      lineDiv.className = 'frontmatter-line';

      // Add key
      const keySpan = document.createElement('span');
      keySpan.className = 'frontmatter-key';
      keySpan.textContent = 'file: ';
      lineDiv.appendChild(keySpan);

      // Create clickable link
      const link = document.createElement('a');
      link.className = 'frontmatter-link';
      link.textContent = displayPath;
      link.title = filePath; // Show full path on hover
      link.href = '#';

      // Handle click to open in editor
      link.addEventListener('click', async (e) => {
        e.preventDefault();
        e.stopPropagation();

        try {
          // First, insert the command into textarea
          if (this.callbacks.onSelectSkill) {
            this.callbacks.onSelectSkill(command);
          }

          // Then, open the file in editor
          this.callbacks.onBeforeOpenFile?.();
          this.callbacks.setDraggable?.(true);
          const result = await window.electronAPI?.file?.openInEditor?.(filePath);

          if (!result?.success && result?.error) {
            console.error('Failed to open file:', result.error);
            this.callbacks.setDraggable?.(false);
          }
          // Note: Do not restore focus to PromptLine window
          // The opened file's application should stay in foreground
        } catch (err) {
          console.error('Failed to open file in editor:', err);
          this.callbacks.setDraggable?.(false);
        }
      });

      lineDiv.appendChild(link);
      contentDiv.appendChild(lineDiv);
    } catch (error) {
      // Silently fail - file link is optional
      console.error('Failed to add file path line:', error);
    }
  }


  /**
   * Show the frontmatter popup for a command
   */
  public show(command: AgentSkillItemLike, targetElement: HTMLElement): void {
    const suggestionsContainer = this.callbacks.getSuggestionsContainer();
    if (!this.frontmatterPopup || !command.tooltip || !suggestionsContainer) return;

    // Cancel any pending hide
    this.cancelHide();

    // Clear previous content using safe DOM method
    while (this.frontmatterPopup.firstChild) {
      this.frontmatterPopup.removeChild(this.frontmatterPopup.firstChild);
    }

    // Create content container with parsed frontmatter
    const contentDiv = document.createElement('div');
    contentDiv.className = 'frontmatter-content';
    renderFrontmatter(contentDiv, command.tooltip);

    // Add file path line as last frontmatter item (before hint)
    this.addFilePathLine(contentDiv, command);

    this.frontmatterPopup.appendChild(contentDiv);

    // Add hint message at the bottom
    const hintDiv = document.createElement('div');
    hintDiv.className = 'frontmatter-hint';
    hintDiv.textContent = this.autoShowTooltip ? 'Ctrl+i: hide tooltip' : 'Ctrl+i: auto-show tooltip';
    this.frontmatterPopup.appendChild(hintDiv);

    // Calculate popup position using shared utility
    const position = calculatePopupPosition({
      targetRect: targetElement.getBoundingClientRect(),
      containerRect: suggestionsContainer.getBoundingClientRect()
    });

    // Apply position to popup
    applyPopupPosition(this.frontmatterPopup, position);

    this.frontmatterPopup.style.display = 'block';
    this.isPopupVisible = true;

    // Set up row listeners for tooltip persistence
    this.setupRowListeners(targetElement);
  }

  /**
   * Hide the frontmatter popup
   */
  public hide(): void {
    if (this.frontmatterPopup) {
      this.frontmatterPopup.style.display = 'none';
    }
    this.isPopupVisible = false;
    // Clean up row listeners when popup is hidden
    this.cleanupRowListeners();
  }

  /**
   * Schedule popup hide with delay
   */
  public scheduleHide(): void {
    this.cancelHide();
    this.popupHideTimeout = setTimeout(() => {
      this.hide();
    }, FrontmatterPopupManager.POPUP_HIDE_DELAY);
  }

  /**
   * Cancel pending popup hide
   */
  public cancelHide(): void {
    if (this.popupHideTimeout) {
      clearTimeout(this.popupHideTimeout);
      this.popupHideTimeout = null;
    }
  }

  /**
   * Clean up row event listeners
   */
  private cleanupRowListeners(): void {
    if (this.currentRowElement && this.boundRowMouseEnter && this.boundRowMouseLeave) {
      this.currentRowElement.removeEventListener('mouseenter', this.boundRowMouseEnter);
      this.currentRowElement.removeEventListener('mouseleave', this.boundRowMouseLeave);
    }
    this.currentRowElement = null;
    this.boundRowMouseEnter = null;
    this.boundRowMouseLeave = null;
  }

  /**
   * Set up row event listeners for tooltip persistence
   */
  private setupRowListeners(targetElement: HTMLElement): void {
    // Clean up previous row listeners
    this.cleanupRowListeners();

    // Find the parent row element
    const rowElement = targetElement.closest('.agent-skill-suggestion-item');
    if (!rowElement) return;

    // Create bound handlers
    this.boundRowMouseEnter = () => this.cancelHide();
    this.boundRowMouseLeave = () => this.scheduleHide();

    // Add listeners to the row
    rowElement.addEventListener('mouseenter', this.boundRowMouseEnter);
    rowElement.addEventListener('mouseleave', this.boundRowMouseLeave);
    this.currentRowElement = rowElement;
  }

  /**
   * Show tooltip for the currently selected item (if auto-show is enabled)
   */
  public showForSelectedItem(): void {
    const suggestionsContainer = this.callbacks.getSuggestionsContainer();
    if (!this.autoShowTooltip || !suggestionsContainer) return;

    const filteredSkills = this.callbacks.getFilteredSkills();
    const selectedIndex = this.callbacks.getSelectedIndex();
    const selectedSkill = filteredSkills[selectedIndex];
    if (!selectedSkill?.tooltip) {
      this.hide();
      return;
    }

    // Find the info icon element for the selected item
    const selectedItem = suggestionsContainer.querySelector('.agent-skill-suggestion-item.selected');
    const infoIcon = selectedItem?.querySelector('.frontmatter-info-icon') as HTMLElement;
    if (infoIcon) {
      this.show(selectedSkill, infoIcon);
    }
  }

  /**
   * Toggle auto-show tooltip mode
   */
  public toggleAutoShow(): void {
    this.autoShowTooltip = !this.autoShowTooltip;
    if (this.autoShowTooltip) {
      this.showForSelectedItem();
    } else {
      this.hide();
    }
  }

  /**
   * Get whether auto-show tooltip is enabled
   */
  public isAutoShowEnabled(): boolean {
    return this.autoShowTooltip;
  }

  /**
   * Get whether popup is currently visible
   */
  public getIsVisible(): boolean {
    return this.isPopupVisible;
  }

  /**
   * Clean up resources
   */
  public destroy(): void {
    this.cancelHide();
    this.cleanupRowListeners();
    if (this.frontmatterPopup && this.frontmatterPopup.parentNode) {
      this.frontmatterPopup.parentNode.removeChild(this.frontmatterPopup);
      this.frontmatterPopup = null;
    }
  }
}
