import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges, computed, signal } from '@angular/core';
import { SectionConfig } from '../../shared/models/config';
import { HeroSlideData, HeroWidgetData } from '../contracts/widget-data.contract';
import { TranslatePipe } from '../../i18n/translate.pipe';

const AUTOPLAY_INTERVAL_MS = 5000;
const SWIPE_THRESHOLD_PX = 50;

@Component({
  selector: 'app-hero-widget',
  standalone: true,
  imports: [CommonModule, TranslatePipe],
  template: `
    <section class="hero-widget">
      @if (visibleSlides().length) {
        <div class="hero-widget__nav">
          @if (allSlides().length > 1) {
            <button
              type="button"
              class="hero-widget__arrow hero-widget__arrow--prev"
              [attr.aria-label]="'common.previousSlide' | translate"
              (click)="prevSlide()"
            >&larr;</button>
          }

          <div class="hero-widget__slides" (touchstart)="onSwipeStart($event)" (touchend)="onSwipeEnd($event)">
            @for (slide of visibleSlides(); track $index) {
              <article class="hero-widget__slide">
                <h2 class="hero-widget__title">{{ slide.title }}</h2>
                @if (slide.subtitle) {
                  <p class="hero-widget__subtitle">{{ slide.subtitle }}</p>
                }
                @if (slide.ctaLabel) {
                  <button type="button" class="hero-widget__cta" (click)="onCtaClick()">{{ slide.ctaLabel }}</button>
                }
              </article>
            }
          </div>

          @if (allSlides().length > 1) {
            <button
              type="button"
              class="hero-widget__arrow hero-widget__arrow--next"
              [attr.aria-label]="'common.nextSlide' | translate"
              (click)="nextSlide()"
            >&rarr;</button>
          }
        </div>

        @if (allSlides().length > 1) {
          <div class="hero-widget__dots" role="tablist" [attr.aria-label]="'common.slidesLabel' | translate">
            @for (dot of allSlides(); track $index) {
              <button
                type="button"
                class="hero-widget__dot"
                [class.hero-widget__dot--active]="$index === activeIndex()"
                role="tab"
                [attr.aria-selected]="$index === activeIndex()"
                [attr.aria-label]="'common.slideLabel' | translate:{ value: $index + 1 }"
                (click)="goTo($index)"
              ></button>
            }
            @if (data?.autoplay) {
              <button
                type="button"
                class="hero-widget__pause"
                [attr.aria-label]="(isPaused() ? 'common.resumeAutoplay' : 'common.pauseAutoplay') | translate"
                [attr.aria-pressed]="isPaused()"
                (click)="toggleAutoplay()"
              >{{ isPaused() ? '▶' : '⏸' }}</button>
            }
          </div>
        }
      }
    </section>
  `,
  styles: [
    `
      .hero-widget {
        position: relative;
        padding: var(--space-xl, 32px);
        border-radius: var(--radius-lg, 16px);
        background: linear-gradient(135deg, var(--bg-secondary, #f5f5f5) 0%, var(--bg-tertiary, #eef1f0) 100%);
        animation: hero-widget-in 420ms ease-out both;
      }

      .hero-widget__nav {
        display: flex;
        align-items: stretch;
        gap: var(--space-sm, 8px);
      }

      .hero-widget__slides {
        flex: 1;
        min-width: 0;
        display: flex;
        gap: var(--space-lg, 24px);
      }

      .hero-widget__slide {
        flex: 1 1 0;
        min-width: 0;
      }

      .hero-widget__arrow {
        flex-shrink: 0;
        align-self: center;
        width: 40px;
        height: 40px;
        border-radius: 50%;
        border: 1px solid var(--border-color, #d3dad9);
        background: #fff;
        color: var(--text-primary, #1e3c38);
        cursor: pointer;
        font-size: 1rem;

        &:hover { background: var(--primary-color, #497671); color: #fff; }
        &:focus-visible { outline: 2px solid var(--primary-color, #497671); outline-offset: 2px; }
      }

      .hero-widget__title {
        margin: 0 0 var(--space-sm, 8px);
        font-size: 2rem;
        font-weight: 700;
        color: var(--text-primary, #1e3c38);
        animation: hero-widget-in 480ms ease-out 60ms both;
      }

      .hero-widget__subtitle {
        margin: 0 0 var(--space-lg, 24px);
        color: var(--text-secondary, #667a77);
        font-size: 1.05rem;
        animation: hero-widget-in 480ms ease-out 120ms both;
      }

      .hero-widget__cta {
        border: 1px solid transparent;
        border-radius: var(--radius-md, 12px);
        padding: 0.75rem 1.5rem;
        cursor: pointer;
        font-weight: 600;
        background: var(--primary-color, #497671);
        color: #fff;
        transition: transform var(--transition-normal, 180ms ease), box-shadow var(--transition-normal, 180ms ease), background-color var(--transition-normal, 180ms ease);
        animation: hero-widget-in 480ms ease-out 180ms both;

        &:hover {
          background: var(--primary-hover, #3d635f);
          transform: translateY(-2px);
          box-shadow: var(--shadow-md, 0 4px 12px rgba(0, 0, 0, 0.15));
        }

        &:active {
          transform: translateY(0);
        }

        &:focus-visible {
          outline: 2px solid var(--primary-color, #497671);
          outline-offset: 2px;
        }
      }

      .hero-widget__dots {
        display: flex;
        gap: 8px;
        margin-top: var(--space-lg, 24px);
      }

      .hero-widget__dot {
        width: 10px;
        height: 10px;
        border-radius: 50%;
        border: none;
        background: rgba(0, 0, 0, 0.2);
        cursor: pointer;
        padding: 0;

        &--active { background: var(--primary-color, #497671); }
        &:focus-visible { outline: 2px solid var(--primary-color, #497671); outline-offset: 2px; }
      }

      .hero-widget__pause {
        margin-left: var(--space-sm, 8px);
        width: 24px;
        height: 24px;
        border-radius: 50%;
        border: 1px solid var(--border-color, #d3dad9);
        background: #fff;
        cursor: pointer;
        font-size: 0.7rem;
        line-height: 1;
        display: inline-flex;
        align-items: center;
        justify-content: center;

        &:focus-visible { outline: 2px solid var(--primary-color, #497671); outline-offset: 2px; }
      }

      @keyframes hero-widget-in {
        from { opacity: 0; transform: translateY(12px); }
        to { opacity: 1; transform: translateY(0); }
      }

      @media (prefers-reduced-motion: reduce) {
        .hero-widget,
        .hero-widget__title,
        .hero-widget__subtitle,
        .hero-widget__cta {
          animation: none;
        }

        .hero-widget__cta {
          transition: none;
        }
      }
    `
  ],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class HeroWidgetComponent implements OnChanges, OnDestroy {
  @Input() section: SectionConfig | null = null;
  @Input() data: HeroWidgetData | null = null;

  @Output() ctaClicked = new EventEmitter<void>();

  readonly activeIndex = signal(0);
  readonly isPaused = signal(false);
  private readonly dataSignal = signal<HeroWidgetData | null>(null);
  private autoplayHandle: ReturnType<typeof setInterval> | null = null;
  private swipeStartX: number | null = null;

  readonly allSlides = computed<HeroSlideData[]>(() => {
    const current = this.dataSignal();
    if (!current) {
      return [];
    }
    const primary: HeroSlideData = { title: current.title, subtitle: current.subtitle, ctaLabel: current.ctaLabel };
    return [primary, ...(current.slides ?? [])];
  });

  readonly activeSlide = computed<HeroSlideData | null>(() => this.allSlides()[this.activeIndex()] ?? null);

  /** 1 or 2, reusing `layout.columns` (no dedicated "slides per page" field). 2 has nothing to show a second panel with when there's only one slide. */
  get panelCount(): number {
    const requested = this.section?.layout?.columns === 2 ? 2 : 1;
    return requested === 2 && this.allSlides().length > 1 ? 2 : 1;
  }

  visibleSlides(): HeroSlideData[] {
    const slides = this.allSlides();
    if (slides.length === 0) {
      return [];
    }
    if (this.panelCount === 2) {
      const nextIndex = (this.activeIndex() + 1) % slides.length;
      return [slides[this.activeIndex()], slides[nextIndex]];
    }
    const current = slides[this.activeIndex()];
    return current ? [current] : [];
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes['data']) {
      this.dataSignal.set(this.data);
      this.activeIndex.set(0);
      this.isPaused.set(false);
      this.setupAutoplay();
    }
  }

  ngOnDestroy(): void {
    this.clearAutoplay();
  }

  goTo(index: number): void {
    this.activeIndex.set(index);
    this.setupAutoplay();
  }

  prevSlide(): void {
    const total = this.allSlides().length;
    if (total <= 1) {
      return;
    }
    this.goTo((this.activeIndex() - 1 + total) % total);
  }

  nextSlide(): void {
    const total = this.allSlides().length;
    if (total <= 1) {
      return;
    }
    this.goTo((this.activeIndex() + 1) % total);
  }

  onSwipeStart(event: TouchEvent): void {
    this.swipeStartX = event.touches[0]?.clientX ?? null;
  }

  onSwipeEnd(event: TouchEvent): void {
    const startX = this.swipeStartX;
    this.swipeStartX = null;
    if (startX === null) {
      return;
    }
    const endX = event.changedTouches[0]?.clientX ?? startX;
    const diff = startX - endX;
    if (diff > SWIPE_THRESHOLD_PX) {
      this.nextSlide();
    } else if (diff < -SWIPE_THRESHOLD_PX) {
      this.prevSlide();
    }
  }

  onCtaClick(): void {
    this.ctaClicked.emit();
  }

  /** WCAG 2.2.2: auto-updating content lasting >5s needs a way to pause it. */
  toggleAutoplay(): void {
    this.isPaused.update(paused => !paused);
    this.setupAutoplay();
  }

  private prefersReducedMotion(): boolean {
    return typeof window !== 'undefined' && !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
  }

  private setupAutoplay(): void {
    this.clearAutoplay();
    const slides = this.allSlides();
    if (!this.data?.autoplay || slides.length <= 1 || this.isPaused() || this.prefersReducedMotion()) {
      return;
    }
    this.autoplayHandle = setInterval(() => {
      this.activeIndex.update(index => (index + 1) % slides.length);
    }, AUTOPLAY_INTERVAL_MS);
  }

  private clearAutoplay(): void {
    if (this.autoplayHandle !== null) {
      clearInterval(this.autoplayHandle);
      this.autoplayHandle = null;
    }
  }
}
