import {
  ChangeDetectionStrategy,
  Component,
  computed,
  DestroyRef,
  effect,
  inject,
  OnInit,
  signal,
  untracked,
} from '@angular/core';
import { FormsModule } from '@angular/forms';
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
import { MissionStateResponse } from '@fog-explorer/api-interfaces';
import { SURVIVOR_NAMES } from '@fog-explorer/encounter-library';
import { avatarUrl } from './survivor-initials';
import { distinctUntilChanged, filter, skip } from 'rxjs';
import { MissionStateStore } from '../mission/mission-state.store';
import { TwitchAuthService } from '../twitch/twitch-auth.service';
import { AmbientEventComponent, AmbientEventData } from './ambient-event.component';
import { ExpandedPanelComponent } from './expanded-panel.component';
import { MinimisedPanelComponent } from './minimised-panel.component';
import { SummaryPanelComponent } from './summary-panel.component';

type OverlayView = 'minimised' | 'ambient' | 'expanded';

function detectAmbientEvent(
  prev: NonNullable<MissionStateResponse>,
  curr: NonNullable<MissionStateResponse>
): AmbientEventData | null {
  if (curr.mission.status === 'success' && prev.mission.status !== 'success') {
    return { type: 'mission-complete', description: 'Mission complete.' };
  }
  if (curr.mission.status === 'sacrifice' && prev.mission.status !== 'sacrifice') {
    return { type: 'sacrifice', description: 'Sacrificed to the fog.' };
  }
  for (const survivor of curr.survivors) {
    const prevSurvivor = prev.survivors.find((s) => s.id === survivor.id);
    if (prevSurvivor && survivor.state !== prevSurvivor.state) {
      if (survivor.state === 'injured' || survivor.state === 'downed') {
        return { type: 'injury', description: `${survivor.name} is injured.` };
      }
    }
  }
  return null;
}

@Component({
  selector: 'app-panel-shell',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [FormsModule, MinimisedPanelComponent, AmbientEventComponent, ExpandedPanelComponent, SummaryPanelComponent],
  templateUrl: './panel-shell.component.html',
  styleUrl: './panel-shell.component.css',
})
export class PanelShellComponent implements OnInit {
  protected readonly authService = inject(TwitchAuthService);
  protected readonly store = inject(MissionStateStore);
  private readonly destroyRef = inject(DestroyRef);

  protected readonly view = signal<OverlayView>('minimised');
  protected readonly pendingEvent = signal<AmbientEventData | null>(null);
  protected readonly selectedCharacter = signal<string | null>(null);
  protected readonly selectedDifficulty = signal<1 | 2 | 3 | null>(null);
  protected readonly characterFilter = signal('');

  protected readonly survivorNames = SURVIVOR_NAMES;
  protected readonly avatarUrl = avatarUrl;
  protected readonly filteredSurvivors = computed(() => {
    const q = this.characterFilter().toLowerCase().trim();
    return q ? SURVIVOR_NAMES.filter((n) => n.toLowerCase().includes(q)) : SURVIVOR_NAMES;
  });

  protected readonly missionIsActive = computed(
    () => this.store.state()?.mission.status === 'active',
  );
  protected readonly terminalOutcome = computed(() => {
    const status = this.store.state()?.mission.status;
    if (status === 'success') return 'The expedition is complete.';
    if (status === 'sacrifice') return 'Taken by the fog.';
    if (status === 'abandoned') return 'The expedition was abandoned.';
    return null;
  });

  protected readonly summaryDismissed = signal(false);
  protected readonly showSummary = computed(() => {
    const status = this.store.state()?.mission.status;
    return (status === 'success' || status === 'sacrifice') && !this.summaryDismissed();
  });

  private prevState: MissionStateResponse = null;
  private ambientTimer: ReturnType<typeof setTimeout> | null = null;

  constructor() {
    // Visibility restore → reconcile missed ticks.
    // skip(1) prevents a double-fetch on startup (initial isVisible value is true).
    toObservable(this.authService.isVisible).pipe(
      distinctUntilChanged(),
      skip(1),
      filter(Boolean),
      takeUntilDestroyed(this.destroyRef),
    ).subscribe(() => this.store.refresh());

    // Detect significant state changes and trigger ambient events.
    effect(() => {
      const current = this.store.state();
      untracked(() => this.handleStateChange(current));
    });

    // Reset summary gate when a fresh active mission arrives.
    effect(() => {
      if (this.store.state()?.mission.status === 'active') {
        untracked(() => this.summaryDismissed.set(false));
      }
    });
  }

  ngOnInit(): void {
    this.authService.init();
    this.store.init();
  }

  protected onLanternClick(): void {
    this.view.update((v) => (v === 'expanded' ? 'minimised' : 'expanded'));
  }

  protected onSelectCharacter(name: string): void {
    this.selectedCharacter.set(name);
    this.characterFilter.set('');
  }

  protected onSelectRandomCharacter(): void {
    const names = SURVIVOR_NAMES;
    const picked = names[Math.floor(Math.random() * names.length)];
    this.selectedCharacter.set(picked);
    this.characterFilter.set('');
  }

  protected onBackToCharacter(): void {
    this.selectedCharacter.set(null);
    this.selectedDifficulty.set(null);
    this.characterFilter.set('');
  }

  protected onSelectDifficulty(difficulty: 1 | 2 | 3): void {
    this.selectedDifficulty.set(difficulty);
  }

  protected onSelectDuration(durationMinutes: 10 | 20 | 30): void {
    const difficulty = this.selectedDifficulty();
    if (!difficulty) return;
    this.store.startMission(difficulty, durationMinutes, this.selectedCharacter() ?? undefined);
  }

  protected onBackToDifficulty(): void {
    this.selectedDifficulty.set(null);
  }

  protected onAbandon(): void {
    this.store.abandonMission();
    this.view.set('minimised');
  }

  protected onContinueAfterSummary(): void {
    this.summaryDismissed.set(true);
    this.selectedCharacter.set(null);
    this.selectedDifficulty.set(null);
  }

  protected onAmbientDismiss(): void {
    this.clearAmbientTimer();
    this.view.set('minimised');
    this.pendingEvent.set(null);
  }

  private handleStateChange(current: MissionStateResponse): void {
    const prev = this.prevState;
    this.prevState = current;

    if (!prev || !current) return;
    if (this.view() === 'expanded') return; // Don't interrupt expanded view
    if (!this.authService.isVisible()) return; // Drop events while hidden

    const event = detectAmbientEvent(prev, current);
    if (!event) return;

    this.clearAmbientTimer();
    this.pendingEvent.set(event);
    this.view.set('ambient');
    this.ambientTimer = setTimeout(() => this.onAmbientDismiss(), 4000);
  }

  private clearAmbientTimer(): void {
    if (this.ambientTimer !== null) {
      clearTimeout(this.ambientTimer);
      this.ambientTimer = null;
    }
  }
}
