/**
 * Header 自动隐藏/显示控制
 * - 页面顶部时固定展示
 * - 滚动离开顶部后隐藏，鼠标移动到顶部区域或焦点进入时显示
 */

class HeaderVisibilityController {
  private header: HTMLElement | null = null;
  private isAtTop = true;
  private isMouseInHeaderZone = false;
  private isMouseNearRevealZone = false;
  private visibilityState: 'visible' | 'hidden' | 'animating-show' | 'animating-hide' = 'visible';
  private readonly pinThreshold = 56;
  private readonly revealZoneHeight = 120;
  private pointerState: {
    currentX: number;
    currentY: number;
    currentIntensity: number;
    targetX: number;
    targetY: number;
    targetIntensity: number;
    rafId: number | null;
  } = {
    currentX: 50,
    currentY: -40,
    currentIntensity: 0,
    targetX: 50,
    targetY: -40,
    targetIntensity: 0,
    rafId: null
  };

  constructor() {
    this.init();
  }

  private init(): void {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', () => this.setup());
    } else {
      this.setup();
    }
  }

  private setup(): void {
    this.header = document.getElementById('site-header');
    if (!this.header) return;

    this.isAtTop = window.scrollY <= this.pinThreshold;
    this.visibilityState = 'visible';
    this.header.classList.remove('hidden', 'hiding', 'showing');
    this.header.classList.add('visible');
    if (this.isAtTop) {
      this.header.classList.add('pinned');
    }
    window.addEventListener('scroll', () => this.handleScroll(), { passive: true });
    window.addEventListener('mousemove', (event) => this.handleMouseMove(event));

    this.header.addEventListener('focusin', () => this.handleFocusIn());
    this.header.addEventListener('focusout', () => this.handleFocusOut());
    this.header.addEventListener('animationend', (event) => this.handleAnimationEnd(event));

    if (!this.pointerState.rafId) {
      this.pointerState.rafId = window.requestAnimationFrame(() => this.runPointerAnimation());
    }

    // 初始状态
    this.handleScroll();
  }

  private handleScroll(): void {
    if (!this.header) return;

  const atTop = window.scrollY <= this.pinThreshold;
  this.isAtTop = atTop;

    if (atTop) {
      this.header.classList.add('pinned');
      this.showHeader();
    } else {
      this.header.classList.remove('pinned');
      if (!this.isMouseInHeaderZone && !this.isMouseNearRevealZone) {
        this.hideHeader();
      }
    }

  }

  private handleMouseMove(event: MouseEvent): void {
    if (!this.header) return;

    this.checkMouseZone(event);
    this.updateRevealZone(event);
    this.updatePointerFromEvent(event);
  }

  private handleFocusIn(): void {
    this.showHeader();
    this.setPointerTarget(50, 35, 0.75);
  }

  private handleFocusOut(): void {
    if (!this.header) return;
    window.requestAnimationFrame(() => {
      const active = document.activeElement;
      if (active && this.header && this.header.contains(active)) {
        return;
      }
      if (!this.isAtTop && !this.isMouseInHeaderZone && !this.isMouseNearRevealZone) {
        this.hideHeader();
      }
      this.setPointerTarget(50, -40, 0);
    });
  }

  private showHeader(options: { animate?: boolean } = {}): void {
    if (!this.header) return;
    const animate = options.animate ?? true;

    if (!animate) {
      if (this.visibilityState === 'visible') return;
      this.visibilityState = 'visible';
      this.header.classList.remove('hidden', 'hiding', 'showing');
      this.header.classList.add('visible');
      return;
    }

    if (this.visibilityState === 'visible' || this.visibilityState === 'animating-show') {
      return;
    }

    this.visibilityState = 'animating-show';
    this.header.classList.remove('hidden', 'hiding');
    this.header.classList.add('visible', 'showing');
  }

  private hideHeader(options: { animate?: boolean; resetPointer?: boolean } = {}): void {
    if (!this.header) return;
    const animate = options.animate ?? true;
    const resetPointer = options.resetPointer ?? true;

    if (!animate) {
      if (this.visibilityState === 'hidden') return;
      this.visibilityState = 'hidden';
      this.header.classList.remove('visible', 'showing', 'hiding');
      this.header.classList.add('hidden');
      if (resetPointer) {
        this.setPointerTarget(50, -40, 0);
      }
      return;
    }

    if (this.visibilityState === 'hidden' || this.visibilityState === 'animating-hide') {
      return;
    }

    this.visibilityState = 'animating-hide';
    this.header.classList.remove('showing');
    this.header.classList.add('hiding');
    if (resetPointer) {
      this.setPointerTarget(50, -40, 0);
    }
  }

  private setPointerTarget(x: number, y: number, intensity: number): void {
    this.pointerState.targetX = this.clamp(x, 0, 100);
    this.pointerState.targetY = this.clamp(y, -60, 140);
    this.pointerState.targetIntensity = this.clamp(intensity, 0, 1.1);
  }

  private checkMouseZone(event: MouseEvent): void {
    if (!this.header) return;
    const rect = this.header.getBoundingClientRect();
    const headerHeight = Math.max(this.header.offsetHeight, 80);
    const headerWidth = Math.max(rect.width, this.header.offsetWidth || window.innerWidth);
    const headerLeft = rect.left || 0;
    const headerTop = Math.max(rect.top, 0);
    const headerRight = headerLeft + headerWidth;
    const headerBottom = headerTop + headerHeight;

    const inHeaderZone =
      event.clientY >= headerTop &&
      event.clientY <= headerBottom &&
      event.clientX >= headerLeft &&
      event.clientX <= headerRight;

    const wasInZone = this.isMouseInHeaderZone;
    this.isMouseInHeaderZone = inHeaderZone;

    // 鼠标进入header区域时显示
    if (inHeaderZone && !wasInZone) {
      this.showHeader();
    }
    // 鼠标离开header区域且不在顶部时隐藏
    else if (!inHeaderZone && wasInZone && !this.isAtTop && !this.isMouseNearRevealZone) {
      this.hideHeader();
    }
  }

  private updateRevealZone(event: MouseEvent): void {
    if (!this.header) return;

    const wasNearZone = this.isMouseNearRevealZone;
    const inRevealZone = !this.isAtTop && event.clientY >= 0 && event.clientY <= this.revealZoneHeight;

    this.isMouseNearRevealZone = inRevealZone;

    if (!this.isAtTop) {
      if (inRevealZone && !wasNearZone && !this.isMouseInHeaderZone) {
        this.showHeader();
      } else if (!inRevealZone && wasNearZone && !this.isMouseInHeaderZone) {
        this.hideHeader();
      }
    }
  }

  private updatePointerFromEvent(event: MouseEvent): void {
    if (!this.header) return;
    const rect = this.header.getBoundingClientRect();
    const headerHeight = Math.max(this.header.offsetHeight, 80);
    const width = Math.max(rect.width, this.header.offsetWidth || window.innerWidth);
    const left = rect.left;

    // 计算指针位置用于光效
    if (this.isMouseInHeaderZone) {
      const x = width > 0 ? ((event.clientX - left) / width) * 100 : 50;
      const y = headerHeight > 0 ? (event.clientY / headerHeight) * 100 : 50;
      this.setPointerTarget(x, y, 1);
    } else if (this.isMouseNearRevealZone) {
      const x = width > 0 ? ((event.clientX - left) / width) * 100 : 50;
      const y = headerHeight > 0 ? Math.min((event.clientY / headerHeight) * 100, 35) : 20;
      this.setPointerTarget(x, y, 0.5);
    } else {
      // 在附近区域时保持微弱光效
      const nearbyX = event.clientX >= left - 100 && event.clientX <= left + width + 100;
      const nearbyY = event.clientY >= -50 && event.clientY <= headerHeight + 100;

      if (nearbyX && nearbyY) {
        const x = width > 0 ? ((event.clientX - left) / width) * 100 : 50;
        const y = headerHeight > 0 ? (event.clientY / headerHeight) * 100 : 50;
        this.setPointerTarget(x, y, 0.3);
      } else {
        this.setPointerTarget(50, -40, 0);
      }
    }
  }

  private runPointerAnimation(): void {
    if (!this.header) return;

    const lerp = (current: number, target: number, factor: number) => current + (target - current) * factor;

    this.pointerState.currentX = lerp(this.pointerState.currentX, this.pointerState.targetX, 0.09);
    this.pointerState.currentY = lerp(this.pointerState.currentY, this.pointerState.targetY, 0.08);
    this.pointerState.currentIntensity = lerp(this.pointerState.currentIntensity, this.pointerState.targetIntensity, 0.08);

    this.header.style.setProperty('--pointer-x', `${this.pointerState.currentX}%`);
    this.header.style.setProperty('--pointer-y', `${this.pointerState.currentY}%`);
    this.header.style.setProperty('--pointer-intensity', `${this.pointerState.currentIntensity}`);

    this.pointerState.rafId = window.requestAnimationFrame(() => this.runPointerAnimation());
  }

  private handleAnimationEnd(event: AnimationEvent): void {
    if (!this.header || event.target !== this.header) return;
    
    if (event.animationName === 'header-slide-in') {
      if (this.visibilityState !== 'animating-show') {
        return;
      }
      this.header.classList.remove('showing');
      this.visibilityState = 'visible';
    }

    if (event.animationName === 'header-slide-out') {
      if (this.visibilityState !== 'animating-hide') {
        return;
      }
      this.header.classList.remove('hiding');
      this.header.classList.remove('visible');
      this.header.classList.add('hidden');
      this.visibilityState = 'hidden';
    }
  }

  private clamp(value: number, min: number, max: number): number {
    return Math.min(max, Math.max(min, value));
  }
}

// 自动初始化
if (typeof window !== 'undefined') {
  const controller = new HeaderVisibilityController();
  (window as any).headerVisibilityController = controller;
}