import assert from 'node:assert/strict';
import test from 'node:test';
import { normalizeAutodartsEvent, parseDartCode } from './adapter.js';

const cases = [
  ['S1', 1, 1, '1', false, 'Single 1'],
  ['S20', 1, 20, '20', false, 'Single 20'],
  ['D20', 2, 40, '20', false, 'Double 20'],
  ['T19', 3, 57, '19', false, 'Triple 19'],
  ['M20', 0, 0, '20', true, 'Miss at 20'],
  ['D1', 2, 2, '1', false, 'Double 1'],
  ['SB', 1, 25, 'bull', false, 'Single Bull'],
  ['DB', 2, 50, 'bull', false, 'Double Bull']
];

test('parseDartCode parses Autodarts throw codes', () => {
  for (const [code, multiplier, points, segment, isMiss, displayLabel] of cases) {
    assert.deepEqual(parseDartCode(code), {
      dartCode: code,
      multiplier,
      segment,
      points,
      isMiss,
      displayLabel
    });
  }
});

test('normalizeAutodartsEvent maps board throws to throw_recorded', () => {
  for (const [code, multiplier, points, segment, isMiss, displayLabel] of cases) {
    const rawPayload = throwPayload(code);
    const normalized = normalizeAutodartsEvent({
      externalMatchId: 'match-1',
      rawPayload,
      fallbackTopic: 'board-1.events',
      liveMatch: { home_score: 501, away_score: 501 }
    });

    assert.equal(normalized.providerName, 'autodarts_ws');
    assert.equal(normalized.storageEventType, 'throw_recorded');
    assert.equal(normalized.normalizedEventType, 'throw_recorded');
    assert.equal(normalized.normalizedPayload.normalized_event_type, 'throw_recorded');
    assert.equal(normalized.confidenceStatus, 'high');
    assert.deepEqual(normalized.errors, []);
    assert.equal(normalized.rawPayload, rawPayload);
    assert.equal(normalized.scoreChange.dart_code, code);
    assert.equal(normalized.scoreChange.multiplier, multiplier);
    assert.equal(normalized.scoreChange.segment, segment);
    assert.equal(normalized.scoreChange.points, points);
    assert.equal(normalized.scoreChange.throw_score, points);
    assert.equal(normalized.scoreChange.is_miss, isMiss);
    assert.equal(normalized.scoreChange.display_label, displayLabel);
  }
});

test('normalizeAutodartsEvent stores unknown throw payloads as error without crashing', () => {
  const normalized = normalizeAutodartsEvent({
    externalMatchId: 'match-1',
    rawPayload: throwPayload('BOUNCE'),
    fallbackTopic: 'board-1.events',
    liveMatch: { home_score: 501, away_score: 501 }
  });

  assert.equal(normalized.storageEventType, 'error');
  assert.equal(normalized.normalizedEventType, 'error');
  assert.equal(normalized.confidenceStatus, 'low');
  assert.match(normalized.errors.join('\n'), /Unknown Autodarts throw code: BOUNCE/);
});

test('normalizeAutodartsEvent maps Autodarts finish body to match_completed', () => {
  const normalized = normalizeAutodartsEvent({
    externalMatchId: 'match-1',
    rawPayload: {
      channel: 'autodarts.matches',
      topic: 'match-1.events',
      data: {
        event: 'finish',
        id: 'match-1',
        body: {
          id: 'match-1',
          gameScores: [0, 46],
          scores: [{ legs: 3 }, { legs: 0 }],
          gameWinner: 0,
          gameFinished: true,
          players: [{ name: 'Home' }, { name: 'Away' }],
          stats: [
            {
              matchStats: {
                score: 1503,
                average: 42.14,
                dartsThrown: 107,
                checkouts: 8,
                checkoutsHit: 3,
                checkoutPercent: 0.375,
                checkoutPoints: 32,
                plus60: 6,
                plus100: 1,
                plus140: 2,
                plus170: 0,
                total180: 1
              }
            },
            {
              matchStats: {
                score: 1403,
                average: 40.08,
                dartsThrown: 105,
                checkouts: 7,
                checkoutsHit: 0,
                checkoutPercent: 0,
                checkoutPoints: 0,
                plus60: 7,
                plus100: 1,
                plus140: 0,
                plus170: 0,
                total180: 0
              }
            }
          ]
        }
      }
    },
    fallbackTopic: 'match-1.events',
    liveMatch: { home_score: 32, away_score: 46 }
  });

  assert.equal(normalized.storageEventType, 'match_completed');
  assert.equal(normalized.normalizedEventType, 'match_completed');
  assert.equal(normalized.confidenceStatus, 'high');
  assert.equal(normalized.scoreChange.home_score, 0);
  assert.equal(normalized.scoreChange.away_score, 46);
  assert.equal(normalized.scoreChange.game_finished, true);
  assert.equal(normalized.legChange.home_legs, 3);
  assert.equal(normalized.legChange.away_legs, 0);
  assert.equal(normalized.legChange.game_finished, true);
  assert.equal(normalized.normalizedPayload.live_stats.length, 2);
  assert.equal(normalized.normalizedPayload.live_stats[0].legs_won, 3);
  assert.equal(normalized.normalizedPayload.live_stats[0].average, 42.14);
  assert.equal(normalized.normalizedPayload.live_stats[0].darts_thrown, 107);
  assert.equal(normalized.normalizedPayload.live_stats[0].checkout_attempts, 8);
  assert.equal(normalized.normalizedPayload.live_stats[0].checkouts_hit, 3);
  assert.equal(normalized.normalizedPayload.live_stats[0].best_checkout, 32);
  assert.equal(normalized.normalizedPayload.live_stats[0].plus60, 6);
  assert.equal(normalized.normalizedPayload.live_stats[0].plus100, 1);
  assert.equal(normalized.normalizedPayload.live_stats[0].plus140, 2);
  assert.equal(normalized.normalizedPayload.live_stats[0].plus170, 0);
  assert.equal(normalized.normalizedPayload.live_stats[0].total180, 1);
});

test('normalizeAutodartsEvent maps non-terminal gameFinished state to leg_won', () => {
  const normalized = normalizeAutodartsEvent({
    externalMatchId: 'match-1',
    rawPayload: {
      channel: 'autodarts.matches',
      topic: 'match-1.state',
      data: {
        id: 'match-1',
        legs: 3,
        gameScores: [0, 46],
        scores: [{ legs: 1 }, { legs: 0 }],
        gameWinner: 0,
        gameFinished: true,
        players: [{ name: 'Home' }, { name: 'Away' }]
      }
    },
    fallbackTopic: 'match-1.state',
    liveMatch: { home_score: 32, away_score: 46 }
  });

  assert.equal(normalized.storageEventType, 'leg_won');
  assert.equal(normalized.normalizedEventType, 'leg_won');
  assert.equal(normalized.legChange.home_legs, 1);
  assert.equal(normalized.legChange.away_legs, 0);
});

function throwPayload(code) {
  const parsed = parseDartCode(code);
  return {
    channel: 'autodarts.boards',
    topic: 'board-1.events',
    data: {
      event: 'Throw detected',
      boardId: 'board-1',
      throwNumber: 1,
      throw: {
        coords: { x: 0.1, y: 0.2 },
        segment: {
          bed: parsed?.isMiss ? 'Outside' : 'TestBed',
          name: code,
          number: parsed?.segment === 'bull' ? 25 : Number(parsed?.segment ?? 0),
          multiplier: parsed?.multiplier ?? 0
        }
      }
    }
  };
}
