import test from 'node:test';
import assert from 'node:assert/strict';
import {
  createEnsureAnilistMediaGuessHandler,
  createMaybeProbeAnilistDurationHandler,
  type AnilistMediaGuessRuntimeState,
} from './anilist-media-guess';

test('maybeProbeAnilistDuration updates state with probed duration', async () => {
  let state: AnilistMediaGuessRuntimeState = {
    mediaKey: '/tmp/video.mkv',
    mediaDurationSec: null,
    mediaGuess: null,
    mediaGuessPromise: null,
    lastDurationProbeAtMs: 0,
  };
  const probe = createMaybeProbeAnilistDurationHandler({
    getState: () => state,
    setState: (next) => {
      state = next;
    },
    durationRetryIntervalMs: 1000,
    now: () => 2000,
    requestMpvDuration: async () => 321,
    logWarn: () => {},
  });

  const duration = await probe('/tmp/video.mkv');
  assert.equal(duration, 321);
  assert.equal(state.mediaDurationSec, 321);
});

test('maybeProbeAnilistDuration force option bypasses retry interval', async () => {
  let state: AnilistMediaGuessRuntimeState = {
    mediaKey: '/tmp/video.mkv',
    mediaDurationSec: null,
    mediaGuess: null,
    mediaGuessPromise: null,
    lastDurationProbeAtMs: 1900,
  };
  let requestCount = 0;
  const probe = createMaybeProbeAnilistDurationHandler({
    getState: () => state,
    setState: (next) => {
      state = next;
    },
    durationRetryIntervalMs: 1000,
    now: () => 2000,
    requestMpvDuration: async () => {
      requestCount += 1;
      return 321;
    },
    logWarn: () => {},
  });

  const duration = await probe('/tmp/video.mkv', { force: true });

  assert.equal(duration, 321);
  assert.equal(requestCount, 1);
  assert.equal(state.mediaDurationSec, 321);
});

test('ensureAnilistMediaGuess memoizes in-flight guess promise', async () => {
  let state: AnilistMediaGuessRuntimeState = {
    mediaKey: '/tmp/video.mkv',
    mediaDurationSec: null,
    mediaGuess: null,
    mediaGuessPromise: null,
    lastDurationProbeAtMs: 0,
  };
  let calls = 0;
  const ensureGuess = createEnsureAnilistMediaGuessHandler({
    getState: () => state,
    setState: (next) => {
      state = next;
    },
    resolveMediaPathForJimaku: (value) => value,
    getCurrentMediaPath: () => '/tmp/video.mkv',
    getCurrentMediaTitle: () => 'Episode 1',
    guessAnilistMediaInfo: async () => {
      calls += 1;
      return { title: 'Show', season: null, episode: 1, source: 'guessit' };
    },
  });

  const [first, second] = await Promise.all([
    ensureGuess('/tmp/video.mkv'),
    ensureGuess('/tmp/video.mkv'),
  ]);
  assert.deepEqual(first, { title: 'Show', season: null, episode: 1, source: 'guessit' });
  assert.deepEqual(second, { title: 'Show', season: null, episode: 1, source: 'guessit' });
  assert.equal(calls, 1);
  assert.deepEqual(state.mediaGuess, {
    title: 'Show',
    season: null,
    episode: 1,
    source: 'guessit',
  });
  assert.equal(state.mediaGuessPromise, null);
});

test('ensureAnilistMediaGuess skips youtube playback urls', async () => {
  let state: AnilistMediaGuessRuntimeState = {
    mediaKey: 'https://www.youtube.com/watch?v=abc123',
    mediaDurationSec: null,
    mediaGuess: null,
    mediaGuessPromise: null,
    lastDurationProbeAtMs: 0,
  };
  let calls = 0;
  const ensureGuess = createEnsureAnilistMediaGuessHandler({
    getState: () => state,
    setState: (next) => {
      state = next;
    },
    resolveMediaPathForJimaku: (value) => value,
    getCurrentMediaPath: () => 'https://www.youtube.com/watch?v=abc123',
    getCurrentMediaTitle: () => 'Video',
    guessAnilistMediaInfo: async () => {
      calls += 1;
      return { title: 'Show', season: null, episode: 1, source: 'guessit' };
    },
  });

  const guess = await ensureGuess('https://www.youtube.com/watch?v=abc123');
  assert.equal(guess, null);
  assert.equal(calls, 0);
  assert.equal(state.mediaGuess, null);
});
