import { describe, expect, it } from 'vitest';

import {
    RacingDomainValidationError,
} from '../errors/RacingDomainError';

import { SeasonStewardingConfig } from './SeasonStewardingConfig';

describe('SeasonStewardingConfig', () => {
  it('creates a valid config with voting mode and requiredVotes', () => {
    const config = new SeasonStewardingConfig({
      decisionMode: 'steward_vote',
      requiredVotes: 3,
      requireDefense: true,
      defenseTimeLimit: 24,
      voteTimeLimit: 24,
      protestDeadlineHours: 48,
      stewardingClosesHours: 72,
      notifyAccusedOnProtest: true,
      notifyOnVoteRequired: true,
    });

    expect(config.decisionMode).toBe('steward_vote');
    expect(config.requiredVotes).toBe(3);
    expect(config.requireDefense).toBe(true);
    expect(config.defenseTimeLimit).toBe(24);
    expect(config.voteTimeLimit).toBe(24);
    expect(config.protestDeadlineHours).toBe(48);
    expect(config.stewardingClosesHours).toBe(72);
    expect(config.notifyAccusedOnProtest).toBe(true);
    expect(config.notifyOnVoteRequired).toBe(true);
  });

  it('throws when decisionMode is missing', () => {
    expect(
      () =>
        new SeasonStewardingConfig({
          // @ts-expect-error intentional invalid
          decisionMode: undefined,
          requireDefense: true,
          defenseTimeLimit: 24,
          voteTimeLimit: 24,
          protestDeadlineHours: 48,
          stewardingClosesHours: 72,
          notifyAccusedOnProtest: true,
          notifyOnVoteRequired: true,
        }),
    ).toThrow(RacingDomainValidationError);
  });

  it('requires requiredVotes for voting/veto modes', () => {
    const votingModes = [
      'steward_vote',
      'member_vote',
      'steward_veto',
      'member_veto',
    ] as const;

    for (const mode of votingModes) {
      expect(
        () =>
          new SeasonStewardingConfig({
            decisionMode: mode,
            requireDefense: true,
            defenseTimeLimit: 24,
            voteTimeLimit: 24,
            protestDeadlineHours: 48,
            stewardingClosesHours: 72,
            notifyAccusedOnProtest: true,
            notifyOnVoteRequired: true,
          }),
      ).toThrow(RacingDomainValidationError);
    }
  });

  it('validates numeric limits as non-negative / positive integers', () => {
    expect(
      () =>
        new SeasonStewardingConfig({
          decisionMode: 'steward_decides',
          requireDefense: true,
          defenseTimeLimit: -1,
          voteTimeLimit: 24,
          protestDeadlineHours: 48,
          stewardingClosesHours: 72,
          notifyAccusedOnProtest: true,
          notifyOnVoteRequired: true,
        }),
    ).toThrow(RacingDomainValidationError);

    expect(
      () =>
        new SeasonStewardingConfig({
          decisionMode: 'steward_decides',
          requireDefense: true,
          defenseTimeLimit: 24,
          voteTimeLimit: 0,
          protestDeadlineHours: 48,
          stewardingClosesHours: 72,
          notifyAccusedOnProtest: true,
          notifyOnVoteRequired: true,
        }),
    ).toThrow(RacingDomainValidationError);

    expect(
      () =>
        new SeasonStewardingConfig({
          decisionMode: 'steward_decides',
          requireDefense: true,
          defenseTimeLimit: 24,
          voteTimeLimit: 24,
          protestDeadlineHours: 0,
          stewardingClosesHours: 72,
          notifyAccusedOnProtest: true,
          notifyOnVoteRequired: true,
        }),
    ).toThrow(RacingDomainValidationError);

    expect(
      () =>
        new SeasonStewardingConfig({
          decisionMode: 'steward_decides',
          requireDefense: true,
          defenseTimeLimit: 24,
          voteTimeLimit: 24,
          protestDeadlineHours: 48,
          stewardingClosesHours: 0,
          notifyAccusedOnProtest: true,
          notifyOnVoteRequired: true,
        }),
    ).toThrow(RacingDomainValidationError);
  });

  it('equals compares all props', () => {
    const a = new SeasonStewardingConfig({
      decisionMode: 'steward_vote',
      requiredVotes: 3,
      requireDefense: true,
      defenseTimeLimit: 24,
      voteTimeLimit: 24,
      protestDeadlineHours: 48,
      stewardingClosesHours: 72,
      notifyAccusedOnProtest: true,
      notifyOnVoteRequired: true,
    });

    const b = new SeasonStewardingConfig({
      decisionMode: 'steward_vote',
      requiredVotes: 3,
      requireDefense: true,
      defenseTimeLimit: 24,
      voteTimeLimit: 24,
      protestDeadlineHours: 48,
      stewardingClosesHours: 72,
      notifyAccusedOnProtest: true,
      notifyOnVoteRequired: true,
    });

    const c = new SeasonStewardingConfig({
      decisionMode: 'steward_decides',
      requireDefense: false,
      defenseTimeLimit: 0,
      voteTimeLimit: 24,
      protestDeadlineHours: 24,
      stewardingClosesHours: 48,
      notifyAccusedOnProtest: false,
      notifyOnVoteRequired: false,
    });

    expect(a.equals(b)).toBe(true);
    expect(a.equals(c)).toBe(false);
  });
});