import { AdminTrustRatingCalculator, VoteOutcomeInput, SystemSignalInput } from './AdminTrustRatingCalculator';
import { RatingEvent } from '../entities/RatingEvent';
import { RatingEventId } from '../value-objects/RatingEventId';
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
import { RatingDelta } from '../value-objects/RatingDelta';
import { AdminVoteOutcome } from '../entities/AdminVoteSession';

describe('AdminTrustRatingCalculator', () => {
  describe('calculate', () => {
    it('should sum all event deltas', () => {
      const events: RatingEvent[] = [
        RatingEvent.create({
          id: RatingEventId.generate(),
          userId: 'user-123',
          dimension: RatingDimensionKey.create('adminTrust'),
          delta: RatingDelta.create(5),
          occurredAt: new Date(),
          createdAt: new Date(),
          source: { type: 'vote', id: 'vote-123' },
          reason: {
            code: 'ADMIN_VOTE_OUTCOME_POSITIVE',
            summary: 'Test',
            details: {},
          },
          visibility: { public: true, redactedFields: [] },
          version: 1,
        }),
        RatingEvent.create({
          id: RatingEventId.generate(),
          userId: 'user-123',
          dimension: RatingDimensionKey.create('adminTrust'),
          delta: RatingDelta.create(-2),
          occurredAt: new Date(),
          createdAt: new Date(),
          source: { type: 'adminAction', id: 'action-456' },
          reason: {
            code: 'ADMIN_ACTION_REVERSAL_PENALTY',
            summary: 'Test',
            details: {},
          },
          visibility: { public: true, redactedFields: [] },
          version: 1,
        }),
      ];

      const result = AdminTrustRatingCalculator.calculate(events);
      expect(result).toBe(3); // 5 + (-2)
    });

    it('should handle empty events array', () => {
      const result = AdminTrustRatingCalculator.calculate([]);
      expect(result).toBe(0);
    });

    it('should apply weight to deltas', () => {
      const events: RatingEvent[] = [
        RatingEvent.create({
          id: RatingEventId.generate(),
          userId: 'user-123',
          dimension: RatingDimensionKey.create('adminTrust'),
          delta: RatingDelta.create(10),
          weight: 2,
          occurredAt: new Date(),
          createdAt: new Date(),
          source: { type: 'vote', id: 'vote-123' },
          reason: {
            code: 'ADMIN_VOTE_OUTCOME_POSITIVE',
            summary: 'Test',
            details: {},
          },
          visibility: { public: true, redactedFields: [] },
          version: 1,
        }),
      ];

      const result = AdminTrustRatingCalculator.calculate(events);
      expect(result).toBe(20); // 10 * 2
    });

    it('should handle mixed weighted and unweighted events', () => {
      const events: RatingEvent[] = [
        RatingEvent.create({
          id: RatingEventId.generate(),
          userId: 'user-123',
          dimension: RatingDimensionKey.create('adminTrust'),
          delta: RatingDelta.create(5),
          weight: 1,
          occurredAt: new Date(),
          createdAt: new Date(),
          source: { type: 'vote', id: 'vote-123' },
          reason: {
            code: 'ADMIN_VOTE_OUTCOME_POSITIVE',
            summary: 'Test',
            details: {},
          },
          visibility: { public: true, redactedFields: [] },
          version: 1,
        }),
        RatingEvent.create({
          id: RatingEventId.generate(),
          userId: 'user-123',
          dimension: RatingDimensionKey.create('adminTrust'),
          delta: RatingDelta.create(3),
          occurredAt: new Date(),
          createdAt: new Date(),
          source: { type: 'adminAction', id: 'action-456' },
          reason: {
            code: 'ADMIN_ACTION_SLA_BONUS',
            summary: 'Test',
            details: {},
          },
          visibility: { public: true, redactedFields: [] },
          version: 1,
        }),
      ];

      const result = AdminTrustRatingCalculator.calculate(events);
      expect(result).toBe(8); // (5 * 1) + 3
    });
  });

  describe('calculateFromVote', () => {
    it('should calculate positive outcome with full participation', () => {
      const input: VoteOutcomeInput = {
        outcome: {
          percentPositive: 100,
          count: { positive: 10, negative: 0, total: 10 },
          eligibleVoterCount: 10,
          participationRate: 100,
          outcome: 'positive',
        },
        eligibleVoterCount: 10,
        voteCount: 10,
        percentPositive: 100,
      };

      const delta = AdminTrustRatingCalculator.calculateFromVote(input);
      expect(delta.value).toBe(20); // Full positive, full participation
    });

    it('should calculate negative outcome with full participation', () => {
      const input: VoteOutcomeInput = {
        outcome: {
          percentPositive: 0,
          count: { positive: 0, negative: 10, total: 10 },
          eligibleVoterCount: 10,
          participationRate: 100,
          outcome: 'negative',
        },
        eligibleVoterCount: 10,
        voteCount: 10,
        percentPositive: 0,
      };

      const delta = AdminTrustRatingCalculator.calculateFromVote(input);
      expect(delta.value).toBe(-20); // Full negative, full participation
    });

    it('should calculate partial positive outcome', () => {
      const input: VoteOutcomeInput = {
        outcome: {
          percentPositive: 75,
          count: { positive: 3, negative: 1, total: 4 },
          eligibleVoterCount: 4,
          participationRate: 100,
          outcome: 'positive',
        },
        eligibleVoterCount: 4,
        voteCount: 4,
        percentPositive: 75,
      };

      const delta = AdminTrustRatingCalculator.calculateFromVote(input);
      expect(delta.value).toBe(15); // 75% of 20 = 15
    });

    it('should reduce delta for low participation', () => {
      const input: VoteOutcomeInput = {
        outcome: {
          percentPositive: 100,
          count: { positive: 2, negative: 0, total: 2 },
          eligibleVoterCount: 10,
          participationRate: 20,
          outcome: 'positive',
        },
        eligibleVoterCount: 10,
        voteCount: 2,
        percentPositive: 100,
      };

      const delta = AdminTrustRatingCalculator.calculateFromVote(input);
      // 20 * 0.5 (minimum participation multiplier) = 10
      expect(delta.value).toBe(10);
    });

    it('should handle tie outcome', () => {
      const input: VoteOutcomeInput = {
        outcome: {
          percentPositive: 50,
          count: { positive: 5, negative: 5, total: 10 },
          eligibleVoterCount: 10,
          participationRate: 100,
          outcome: 'tie',
        },
        eligibleVoterCount: 10,
        voteCount: 10,
        percentPositive: 50,
      };

      const delta = AdminTrustRatingCalculator.calculateFromVote(input);
      expect(delta.value).toBe(0);
    });

    it('should return zero for no votes', () => {
      const input: VoteOutcomeInput = {
        outcome: {
          percentPositive: 0,
          count: { positive: 0, negative: 0, total: 0 },
          eligibleVoterCount: 10,
          participationRate: 0,
          outcome: 'tie',
        },
        eligibleVoterCount: 10,
        voteCount: 0,
        percentPositive: 0,
      };

      const delta = AdminTrustRatingCalculator.calculateFromVote(input);
      expect(delta.value).toBe(0);
    });

    it('should round to 2 decimal places', () => {
      const input: VoteOutcomeInput = {
        outcome: {
          percentPositive: 66.67,
          count: { positive: 2, negative: 1, total: 3 },
          eligibleVoterCount: 4,
          participationRate: 75,
          outcome: 'positive',
        },
        eligibleVoterCount: 4,
        voteCount: 3,
        percentPositive: 66.67,
      };

      const delta = AdminTrustRatingCalculator.calculateFromVote(input);
      // 66.67% of 20 = 13.334, * 0.75 (participation) = 10.0005, rounded = 10.00
      expect(delta.value).toBe(10.00);
    });
  });

  describe('calculateFromSystemSignal', () => {
    it('should calculate SLA response bonus', () => {
      const input: SystemSignalInput = {
        actionType: 'sla_response',
        details: {},
      };

      const delta = AdminTrustRatingCalculator.calculateFromSystemSignal(input);
      expect(delta.value).toBe(5);
    });

    it('should calculate minor reversal penalty', () => {
      const input: SystemSignalInput = {
        actionType: 'reversal',
        details: {},
        severity: 'minor',
      };

      const delta = AdminTrustRatingCalculator.calculateFromSystemSignal(input);
      expect(delta.value).toBe(-10);
    });

    it('should calculate major reversal penalty', () => {
      const input: SystemSignalInput = {
        actionType: 'reversal',
        details: {},
        severity: 'major',
      };

      const delta = AdminTrustRatingCalculator.calculateFromSystemSignal(input);
      expect(delta.value).toBe(-20);
    });

    it('should calculate rule clarity bonus', () => {
      const input: SystemSignalInput = {
        actionType: 'rule_clarity',
        details: {},
      };

      const delta = AdminTrustRatingCalculator.calculateFromSystemSignal(input);
      expect(delta.value).toBe(3);
    });

    it('should calculate minor abuse report penalty', () => {
      const input: SystemSignalInput = {
        actionType: 'abuse_report',
        details: {},
        severity: 'minor',
      };

      const delta = AdminTrustRatingCalculator.calculateFromSystemSignal(input);
      expect(delta.value).toBe(-15);
    });

    it('should calculate major abuse report penalty', () => {
      const input: SystemSignalInput = {
        actionType: 'abuse_report',
        details: {},
        severity: 'major',
      };

      const delta = AdminTrustRatingCalculator.calculateFromSystemSignal(input);
      expect(delta.value).toBe(-30);
    });

    it('should default to zero for unknown action type', () => {
      const input: SystemSignalInput = {
        actionType: 'sla_response' as any,
        details: {},
      };

      // Override for test
      const delta = AdminTrustRatingCalculator.calculateFromSystemSignal(input);
      expect(delta.value).toBe(5); // Known type
    });
  });

  describe('calculateFromMultipleVotes', () => {
    it('should sum multiple vote outcomes', () => {
      const inputs: VoteOutcomeInput[] = [
        {
          outcome: {
            percentPositive: 100,
            count: { positive: 5, negative: 0, total: 5 },
            eligibleVoterCount: 5,
            participationRate: 100,
            outcome: 'positive',
          },
          eligibleVoterCount: 5,
          voteCount: 5,
          percentPositive: 100,
        },
        {
          outcome: {
            percentPositive: 0,
            count: { positive: 0, negative: 3, total: 3 },
            eligibleVoterCount: 3,
            participationRate: 100,
            outcome: 'negative',
          },
          eligibleVoterCount: 3,
          voteCount: 3,
          percentPositive: 0,
        },
      ];

      const delta = AdminTrustRatingCalculator.calculateFromMultipleVotes(inputs);
      expect(delta.value).toBe(0); // +20 + (-20) = 0
    });
  });

  describe('calculateFromMultipleSystemSignals', () => {
    it('should sum multiple system signals', () => {
      const inputs: SystemSignalInput[] = [
        { actionType: 'sla_response', details: {} },
        { actionType: 'reversal', details: {}, severity: 'minor' },
        { actionType: 'rule_clarity', details: {} },
      ];

      const delta = AdminTrustRatingCalculator.calculateFromMultipleSystemSignals(inputs);
      expect(delta.value).toBe(-2); // 5 + (-10) + 3 = -2
    });
  });

  describe('calculateTotalDelta', () => {
    it('should combine votes and system signals', () => {
      const voteInputs: VoteOutcomeInput[] = [
        {
          outcome: {
            percentPositive: 75,
            count: { positive: 3, negative: 1, total: 4 },
            eligibleVoterCount: 4,
            participationRate: 100,
            outcome: 'positive',
          },
          eligibleVoterCount: 4,
          voteCount: 4,
          percentPositive: 75,
        },
      ];

      const systemInputs: SystemSignalInput[] = [
        { actionType: 'sla_response', details: {} },
        { actionType: 'reversal', details: {}, severity: 'minor' },
      ];

      const delta = AdminTrustRatingCalculator.calculateTotalDelta(voteInputs, systemInputs);
      expect(delta.value).toBe(8); // 15 (vote) + 5 (SLA) + (-10) (reversal) = 10
    });

    it('should handle empty inputs', () => {
      const delta = AdminTrustRatingCalculator.calculateTotalDelta([], []);
      expect(delta.value).toBe(0);
    });
  });
});