import { signal } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { vi } from 'vitest';
import type {
  CurrentLocationConnection,
  CurrentLocationResponse,
  CurrentTravel,
} from '../../core/api/game-api.models';
import { WorldStore } from './world.store';
import { WorldPageComponent } from './world-page.component';

const burnedRoadConnection: CurrentLocationConnection = {
  targetLocation: {
    id: 'burned-road-id',
    key: 'burned-road',
    name: 'Verbrannte Straße',
  },
  travelDurationSeconds: 10,
  danger: 'LOW',
};

const southGate: CurrentLocationResponse = {
  id: 'south-gate-id',
  key: 'south-gate',
  name: 'Südtor von Graufurt',
  description: 'Der letzte sichere Schritt vor den Aschenfeldern.',
  regionKey: 'ashen-fields',
  minRecommendedLevel: 1,
  maxRecommendedLevel: 1,
  dangerLevel: 0,
  isSafe: true,
  huntingEnabled: false,
  artworkPath: '/images/backgrounds/Suedtor.png',
  connections: [burnedRoadConnection],
};

const burnedRoad: CurrentLocationResponse = {
  ...southGate,
  id: 'burned-road-id',
  key: 'burned-road',
  name: 'Verbrannte Straße',
  description: 'Die erste Jagdzone zwischen Asche und zerbrochenen Wagen.',
  isSafe: false,
  huntingEnabled: true,
  artworkPath: '/images/backgrounds/Aschestrasse.png',
  connections: [
    {
      targetLocation: { id: 'south-gate-id', key: 'south-gate', name: 'Südtor von Graufurt' },
      travelDurationSeconds: 10,
      danger: 'LOW',
    },
  ],
};

describe('WorldPageComponent', () => {
  let selectedConnection: ReturnType<typeof signal<CurrentLocationConnection | null>>;
  let store: {
    currentLocation: ReturnType<typeof signal<CurrentLocationResponse | null>>;
    selectedConnection: ReturnType<typeof signal<CurrentLocationConnection | null>>;
    currentTravel: ReturnType<typeof signal<CurrentTravel | null>>;
    remainingSeconds: ReturnType<typeof signal<number | null>>;
    loading: ReturnType<typeof signal<boolean>>;
    error: ReturnType<typeof signal<string | null>>;
    load: () => Promise<void>;
    selectConnection: (connection: CurrentLocationConnection | null) => void;
    startTravel: () => Promise<void>;
  };

  beforeEach(async () => {
    selectedConnection = signal<CurrentLocationConnection | null>(null);
    store = {
      currentLocation: signal(southGate),
      selectedConnection,
      currentTravel: signal<CurrentTravel | null>({ status: 'IDLE' }),
      remainingSeconds: signal<number | null>(null),
      loading: signal(false),
      error: signal<string | null>(null),
      load: vi.fn(() => Promise.resolve()),
      selectConnection: vi.fn((connection: CurrentLocationConnection | null) =>
        selectedConnection.set(connection),
      ),
      startTravel: vi.fn(() => Promise.resolve()),
    };

    await TestBed.configureTestingModule({
      imports: [WorldPageComponent],
      providers: [{ provide: WorldStore, useValue: store }],
    }).compileComponents();
  });

  it('loads world state on initialization', () => {
    const fixture = TestBed.createComponent(WorldPageComponent);

    fixture.detectChanges();

    expect(store.load).toHaveBeenCalledOnce();
  });

  it('selects the burned-road connection and displays its travel details', () => {
    const fixture = TestBed.createComponent(WorldPageComponent);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    element.querySelector<HTMLButtonElement>('[data-location-key="burned-road"]')?.click();
    fixture.detectChanges();

    expect(store.selectConnection).toHaveBeenCalledWith(burnedRoadConnection);
    expect(element.textContent).toContain('Ziel');
    expect(element.textContent).toContain('Verbrannte Straße');
    expect(element.textContent).toContain('00:00:10');
    expect(element.textContent).toContain('Niedrig');
  });

  it('keeps each location at its geographic position when the authoritative current location swaps', () => {
    const fixture = TestBed.createComponent(WorldPageComponent);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    expect(
      element.querySelector('.world-page__node--south-gate [data-location-key="south-gate"]'),
    ).not.toBeNull();
    expect(
      element.querySelector('.world-page__node--burned-road [data-location-key="burned-road"]'),
    ).not.toBeNull();
    expect(element.querySelector('.world-page__scene')?.getAttribute('style')).toContain(
      'map_ashen_realm-1440.jpg',
    );

    store.currentLocation.set(burnedRoad);
    fixture.detectChanges();

    expect(
      element.querySelector('.world-page__node--south-gate [data-location-key="south-gate"]'),
    ).not.toBeNull();
    expect(
      element.querySelector('.world-page__node--burned-road [data-location-key="burned-road"]'),
    ).not.toBeNull();
  });

  it('starts server-authoritative travel from the travel panel', () => {
    const fixture = TestBed.createComponent(WorldPageComponent);
    fixture.detectChanges();
    store.selectConnection(burnedRoadConnection);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    element.querySelector<HTMLButtonElement>('[data-travel-start]')?.click();

    expect(store.startTravel).toHaveBeenCalledOnce();
  });

  it('renders the server-derived countdown while travel is active without enabling another start', () => {
    store.currentTravel.set({
      status: 'TRAVELLING',
      originLocation: { id: 'south-gate-id', key: 'south-gate', name: 'Südtor von Graufurt' },
      targetLocation: burnedRoadConnection.targetLocation,
      startedAt: '2026-08-19T06:00:00.000Z',
      arrivesAt: '2026-08-19T06:00:06.000Z',
    });
    store.remainingSeconds.set(6);
    const fixture = TestBed.createComponent(WorldPageComponent);

    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    expect(element.textContent).toContain('Reiseziel: Verbrannte Straße');
    expect(element.textContent).toContain('Ankunft in');
    expect(element.textContent).toContain('00:00:06');
    expect(element.querySelector<HTMLButtonElement>('[data-travel-start]')?.disabled).toBe(true);
    expect(element.querySelector('app-travel-panel section')?.hasAttribute('aria-live')).toBe(
      false,
    );
    expect(element.querySelector<HTMLElement>('time[role="timer"]')?.textContent).toContain(
      '00:00:06',
    );
  });

  it('locks nodes and selected travel action while authoritative completion reloads', () => {
    store.currentTravel.set({
      status: 'COMPLETED',
      targetLocation: burnedRoadConnection.targetLocation,
    });
    store.loading.set(true);
    store.selectConnection(burnedRoadConnection);
    const fixture = TestBed.createComponent(WorldPageComponent);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    expect(
      element.querySelector<HTMLButtonElement>('[data-location-key="burned-road"]')?.disabled,
    ).toBe(true);
    expect(element.querySelector<HTMLButtonElement>('[data-travel-start]')?.disabled).toBe(true);
  });

  it('retries a displayed world error through the store', () => {
    store.error.set('Weltzustand nicht verfügbar.');
    const fixture = TestBed.createComponent(WorldPageComponent);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    expect(element.querySelector('[role="alert"]')?.textContent).toContain(
      'Weltzustand nicht verfügbar.',
    );
    element.querySelector<HTMLButtonElement>('[data-world-retry]')?.click();

    expect(store.load).toHaveBeenCalledTimes(2);
  });
});
