/**
 * @sc4rfurryx/proteusjs/popover
 * HTML Popover API wrapper with robust focus/inert handling
 * 
 * @version 2.0.0
 * @author sc4rfurry
 * @license MIT
 */

export interface PopoverOptions {
  type?: 'menu' | 'dialog' | 'tooltip';
  trapFocus?: boolean;
  restoreFocus?: boolean;
  closeOnEscape?: boolean;
  onOpen?: () => void;
  onClose?: () => void;
}

export interface PopoverController {
  open(): void;
  close(): void;
  toggle(): void;
  destroy(): void;
}

/**
 * Unified API for menus, tooltips, and dialogs using the native Popover API
 * with robust focus/inert handling
 */
export function attach(
  trigger: Element | string,
  panel: Element | string,
  opts: PopoverOptions = {}
): PopoverController {
  const triggerEl = typeof trigger === 'string' ? document.querySelector(trigger) : trigger;
  const panelEl = typeof panel === 'string' ? document.querySelector(panel) : panel;

  if (!triggerEl || !panelEl) {
    throw new Error('Both trigger and panel elements must exist');
  }

  const {
    type = 'menu',
    trapFocus = type === 'dialog',
    restoreFocus = true,
    closeOnEscape = true,
    onOpen,
    onClose
  } = opts;

  let isOpen = false;
  let previousFocus: Element | null = null;
  let focusTrap: FocusTrap | null = null;

  // Check for native Popover API support
  const hasPopoverAPI = 'popover' in HTMLElement.prototype;

  // Set up ARIA attributes
  const setupAria = () => {
    const panelId = panelEl.id || `popover-${Math.random().toString(36).substr(2, 9)}`;
    panelEl.id = panelId;

    triggerEl.setAttribute('aria-expanded', 'false');
    triggerEl.setAttribute('aria-controls', panelId);

    if (type === 'menu') {
      triggerEl.setAttribute('aria-haspopup', 'menu');
      panelEl.setAttribute('role', 'menu');
    } else if (type === 'dialog') {
      triggerEl.setAttribute('aria-haspopup', 'dialog');
      panelEl.setAttribute('role', 'dialog');
      panelEl.setAttribute('aria-modal', 'true');
    } else if (type === 'tooltip') {
      triggerEl.setAttribute('aria-describedby', panelId);
      panelEl.setAttribute('role', 'tooltip');
    }
  };

  // Set up native popover if supported
  const setupNativePopover = () => {
    if (hasPopoverAPI) {
      (panelEl as any).popover = type === 'dialog' ? 'manual' : 'auto';
      triggerEl.setAttribute('popovertarget', panelEl.id);
    }
  };

  // Focus trap implementation
  class FocusTrap {
    private focusableElements: Element[] = [];

    constructor(private container: Element) {
      this.updateFocusableElements();
    }

    private updateFocusableElements() {
      const selector = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
      this.focusableElements = Array.from(this.container.querySelectorAll(selector));
    }

    activate() {
      this.updateFocusableElements();
      if (this.focusableElements.length > 0) {
        (this.focusableElements[0] as HTMLElement).focus();
      }
      document.addEventListener('keydown', this.handleKeyDown);
    }

    deactivate() {
      document.removeEventListener('keydown', this.handleKeyDown);
    }

    private handleKeyDown = (e: KeyboardEvent) => {
      if (e.key !== 'Tab') return;

      const firstElement = this.focusableElements[0] as HTMLElement;
      const lastElement = this.focusableElements[this.focusableElements.length - 1] as HTMLElement;

      if (e.shiftKey) {
        if (document.activeElement === firstElement) {
          e.preventDefault();
          lastElement.focus();
        }
      } else {
        if (document.activeElement === lastElement) {
          e.preventDefault();
          firstElement.focus();
        }
      }
    };
  }

  const open = () => {
    if (isOpen) return;

    if (restoreFocus) {
      previousFocus = document.activeElement;
    }

    if (hasPopoverAPI) {
      (panelEl as any).showPopover();
    } else {
      (panelEl as HTMLElement).style.display = 'block';
      panelEl.setAttribute('data-popover-open', 'true');
    }

    triggerEl.setAttribute('aria-expanded', 'true');
    isOpen = true;

    if (trapFocus) {
      focusTrap = new FocusTrap(panelEl);
      focusTrap.activate();
    }

    if (onOpen) {
      onOpen();
    }
  };

  const close = () => {
    if (!isOpen) return;

    if (hasPopoverAPI) {
      (panelEl as any).hidePopover();
    } else {
      (panelEl as HTMLElement).style.display = 'none';
      panelEl.removeAttribute('data-popover-open');
    }

    triggerEl.setAttribute('aria-expanded', 'false');
    isOpen = false;

    if (focusTrap) {
      focusTrap.deactivate();
      focusTrap = null;
    }

    if (restoreFocus && previousFocus) {
      (previousFocus as HTMLElement).focus();
      previousFocus = null;
    }

    if (onClose) {
      onClose();
    }
  };

  const toggle = () => {
    if (isOpen) {
      close();
    } else {
      open();
    }
  };

  const handleKeyDown = (e: KeyboardEvent) => {
    if (closeOnEscape && e.key === 'Escape' && isOpen) {
      e.preventDefault();
      close();
    }
  };

  const handleClick = (e: Event) => {
    e.preventDefault();
    toggle();
  };

  const destroy = () => {
    triggerEl.removeEventListener('click', handleClick);
    document.removeEventListener('keydown', handleKeyDown);
    
    if (focusTrap) {
      focusTrap.deactivate();
    }
    
    if (isOpen) {
      close();
    }
  };

  // Initialize
  setupAria();
  setupNativePopover();
  
  triggerEl.addEventListener('click', handleClick);
  document.addEventListener('keydown', handleKeyDown);

  return {
    open,
    close,
    toggle,
    destroy
  };
}

// Export default object for convenience
export default {
  attach
};
