/**
 * Controls Module
 *
 * Handles generic UI controls functionality:
 * - Toggle sliders (Ja/Nej switches)
 * - Select dropdowns
 * - Time range sliders
 */

/**
 * Controller for generic UI controls
 */
export class ControlsController {
  constructor() {
    this.initToggleSliders();
    this.initSelectDropdowns();
    this.initTimeRangeSliders();
  }

  /**
   * Initialize all toggle sliders on the page
   * Toggle slider: Ja/Nej button switch with data-value attribute
   * Clicking anywhere on the slider toggles the value
   */
  private initToggleSliders(): void {
    document.querySelectorAll('swp-toggle-slider').forEach(slider => {
      slider.addEventListener('click', () => {
        const el = slider as HTMLElement;
        const newValue = el.dataset.value === 'yes' ? 'no' : 'yes';
        el.dataset.value = newValue;

        // Dispatch custom event for listeners
        slider.dispatchEvent(new CustomEvent('toggle', {
          bubbles: true,
          detail: { value: newValue }
        }));
      });
    });
  }

  /**
   * Initialize all select dropdowns on the page
   */
  private initSelectDropdowns(): void {
    document.querySelectorAll('swp-select').forEach(select => {
      const trigger = select.querySelector('button');
      const dropdown = select.querySelector('swp-select-dropdown');
      const options = select.querySelectorAll('swp-select-option');

      if (!trigger || !dropdown) return;

      // Toggle dropdown on button click
      trigger.addEventListener('click', (e) => {
        e.stopPropagation();
        const isOpen = select.classList.toggle('open');
        trigger.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
      });

      // Handle option selection
      options.forEach(option => {
        option.addEventListener('click', () => {
          const value = (option as HTMLElement).dataset.value;
          const label = option.textContent?.trim() || '';

          // Update selected state
          options.forEach(o => o.classList.remove('selected'));
          option.classList.add('selected');

          // Update trigger display
          const valueEl = trigger.querySelector('swp-select-value');
          if (valueEl) {
            valueEl.textContent = label;
          }

          // Update color dot if present (for color pickers)
          const triggerDot = trigger.querySelector('swp-color-dot');
          if (triggerDot && value) {
            triggerDot.className = `is-${value}`;
          }

          // Update data-value on select element
          (select as HTMLElement).dataset.value = value;

          // Close dropdown
          select.classList.remove('open');
          trigger.setAttribute('aria-expanded', 'false');

          // Dispatch custom event
          select.dispatchEvent(new CustomEvent('change', {
            bubbles: true,
            detail: { value, label }
          }));
        });
      });
    });

    // Click outside to close any open dropdown
    document.addEventListener('click', () => {
      this.closeAllSelects();
    });

    // Keyboard navigation
    document.addEventListener('keydown', (e) => {
      const openSelect = document.querySelector('swp-select.open');
      if (!openSelect) return;

      // Escape to close
      if (e.key === 'Escape') {
        this.closeAllSelects();
        return;
      }

      // Letter key to jump to option
      if (e.key.length === 1 && /[a-zA-ZæøåÆØÅ]/.test(e.key)) {
        const options = openSelect.querySelectorAll('swp-select-option');
        const letter = e.key.toLowerCase();

        for (const option of options) {
          const text = option.textContent?.trim().toLowerCase() || '';
          if (text.startsWith(letter)) {
            // Scroll into view and highlight
            option.scrollIntoView({ block: 'nearest' });
            options.forEach(o => o.classList.remove('highlighted'));
            option.classList.add('highlighted');
            break;
          }
        }
      }

      // Enter to select highlighted option
      if (e.key === 'Enter') {
        const highlighted = openSelect.querySelector('swp-select-option.highlighted') as HTMLElement;
        if (highlighted) {
          highlighted.click();
        }
      }
    });
  }

  private closeAllSelects(): void {
    document.querySelectorAll('swp-select.open').forEach(select => {
      select.classList.remove('open');
      select.querySelector('button')?.setAttribute('aria-expanded', 'false');
    });
  }

  /**
   * Initialize all time range sliders on the page
   * Each slider gets fill bar positioning, input handling, and drag behavior
   * Dispatches 'timerange:change' event when values change
   */
  private initTimeRangeSliders(): void {
    document.querySelectorAll('swp-time-range-slider').forEach(slider => {
      new TimeRangeSlider(slider as HTMLElement);
    });
  }
}

/**
 * TimeRangeSlider - Reusable dual-handle time range slider
 *
 * Features:
 * - Dual handle (start/end) range inputs
 * - Fill bar that shows selected range
 * - Drag fill bar to move entire range
 * - Label updates with times and duration
 *
 * Dispatches 'timerange:change' event with detail:
 * { start, end, startTime, endTime }
 */
class TimeRangeSlider {
  private static readonly TIME_RANGE_MAX = 60; // 15 hours (06:00-21:00) * 4 intervals

  private slider: HTMLElement;
  private startInput: HTMLInputElement | null;
  private endInput: HTMLInputElement | null;
  private fill: HTMLElement | null;
  private track: HTMLElement | null;

  constructor(slider: HTMLElement) {
    this.slider = slider;
    this.startInput = slider.querySelector('.range-start');
    this.endInput = slider.querySelector('.range-end');
    this.fill = slider.querySelector('swp-time-range-fill');
    this.track = slider.querySelector('swp-time-range-track');

    this.updateDisplay();
    this.setupEventListeners();
    this.setupDragBehavior();
  }

  /**
   * Update the visual display (fill bar position, label text)
   */
  private updateDisplay(): void {
    if (!this.startInput || !this.endInput || !this.fill) return;

    let startVal = parseInt(this.startInput.value);
    let endVal = parseInt(this.endInput.value);

    // Ensure start doesn't exceed end
    if (startVal > endVal) {
      if (this.startInput === document.activeElement) {
        this.startInput.value = String(endVal);
        startVal = endVal;
      } else {
        this.endInput.value = String(startVal);
        endVal = startVal;
      }
    }

    // Update fill bar position
    const startPercent = (startVal / TimeRangeSlider.TIME_RANGE_MAX) * 100;
    const endPercent = (endVal / TimeRangeSlider.TIME_RANGE_MAX) * 100;
    this.fill.style.left = startPercent + '%';
    this.fill.style.width = (endPercent - startPercent) + '%';

    // Update label if exists (inside parent swp-time-range)
    // Supports two patterns:
    // 1. Nested: swp-time-range-label > swp-time-range-times + swp-time-range-duration
    // 2. Simple: swp-time-range-label (direct text content)
    const parent = this.slider.closest('swp-time-range');
    const labelEl = parent?.querySelector('swp-time-range-label');
    const timesEl = parent?.querySelector('swp-time-range-times');
    const durationEl = parent?.querySelector('swp-time-range-duration');

    const timeText = `${this.valueToTime(startVal)} – ${this.valueToTime(endVal)}`;

    if (timesEl) {
      // Nested pattern (employee drawer)
      timesEl.textContent = timeText;
    } else if (labelEl) {
      // Simple pattern (services availability)
      labelEl.textContent = timeText;
    }

    if (durationEl) {
      const durationMinutes = (endVal - startVal) * 15;
      const durationHours = durationMinutes / 60;
      durationEl.textContent = durationHours % 1 === 0
        ? `${durationHours} timer`
        : `${durationHours.toFixed(1).replace('.', ',')} timer`;
    }
  }

  /**
   * Dispatch change event for consumers
   */
  private dispatchChange(): void {
    if (!this.startInput || !this.endInput) return;

    const startVal = parseInt(this.startInput.value);
    const endVal = parseInt(this.endInput.value);

    this.slider.dispatchEvent(new CustomEvent('timerange:change', {
      bubbles: true,
      detail: {
        start: startVal,
        end: endVal,
        startTime: this.valueToTime(startVal),
        endTime: this.valueToTime(endVal)
      }
    }));
  }

  /**
   * Setup input change listeners
   */
  private setupEventListeners(): void {
    this.startInput?.addEventListener('input', () => {
      this.updateDisplay();
      this.dispatchChange();
    });

    this.endInput?.addEventListener('input', () => {
      this.updateDisplay();
      this.dispatchChange();
    });
  }

  /**
   * Setup drag behavior on fill bar to move entire range
   */
  private setupDragBehavior(): void {
    if (!this.fill || !this.track || !this.startInput || !this.endInput) return;

    let isDragging = false;
    let dragStartX = 0;
    let dragStartValues = { start: 0, end: 0 };

    this.fill.addEventListener('mousedown', (e: MouseEvent) => {
      isDragging = true;
      dragStartX = e.clientX;
      dragStartValues.start = parseInt(this.startInput!.value);
      dragStartValues.end = parseInt(this.endInput!.value);
      e.preventDefault();
    });

    document.addEventListener('mousemove', (e: MouseEvent) => {
      if (!isDragging) return;

      const sliderWidth = this.track!.offsetWidth;
      const deltaX = e.clientX - dragStartX;
      const deltaValue = Math.round((deltaX / sliderWidth) * TimeRangeSlider.TIME_RANGE_MAX);

      const duration = dragStartValues.end - dragStartValues.start;
      let newStart = dragStartValues.start + deltaValue;
      let newEnd = dragStartValues.end + deltaValue;

      if (newStart < 0) {
        newStart = 0;
        newEnd = duration;
      }
      if (newEnd > TimeRangeSlider.TIME_RANGE_MAX) {
        newEnd = TimeRangeSlider.TIME_RANGE_MAX;
        newStart = TimeRangeSlider.TIME_RANGE_MAX - duration;
      }

      this.startInput!.value = String(newStart);
      this.endInput!.value = String(newEnd);
      this.updateDisplay();
      this.dispatchChange();
    });

    document.addEventListener('mouseup', () => {
      isDragging = false;
    });
  }

  /**
   * Convert slider value to time string (e.g., 12 → "09:00")
   */
  private valueToTime(value: number): string {
    const totalMinutes = value * 15 + 6 * 60; // Start at 06:00
    const hours = Math.floor(totalMinutes / 60);
    const minutes = totalMinutes % 60;
    return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
  }
}
