import { AdminVoteOutcome } from '../entities/AdminVoteSession';
import { RatingEvent } from '../entities/RatingEvent';
import { RatingDelta } from '../value-objects/RatingDelta';

/**
 * Input for vote outcome calculation
 */
export interface VoteOutcomeInput {
  outcome: AdminVoteOutcome;
  eligibleVoterCount: number;
  voteCount: number;
  percentPositive: number;
}

/**
 * Input for system signal calculation
 */
export interface SystemSignalInput {
  actionType: 'sla_response' | 'reversal' | 'rule_clarity' | 'abuse_report';
  details: Record<string, unknown>;
  severity?: 'minor' | 'major';
}

/**
 * Domain Service: AdminTrustRatingCalculator
 *
 * Pure, stateless calculator for admin trust rating.
 * Implements full logic per ratings-architecture-concept.md sections 5.2 and 7.1.1
 */
export class AdminTrustRatingCalculator {
  /**
   * Calculate admin trust rating delta from events
   *
   * Logic:
   * - Vote outcomes: weighted by participation and percentage
   * - System signals: fixed deltas based on action type
   * - All events are summed with their weights
   */
  static calculate(events: RatingEvent[]): number {
    return events.reduce((sum, event) => {
      // Apply weight if present, otherwise use delta directly
      const weightedDelta = event.weight ? event.delta.value * event.weight : event.delta.value;
      return sum + weightedDelta;
    }, 0);
  }

  /**
   * Calculate delta from vote outcome
   *
   * Based on section 5.2.1:
   * - Votes produce events with reference to voteSessionId
   * - Delta is weighted by eligible voter count and participation
   * - Range: -20 to +20 based on percentage
   *
   * @param input - Vote outcome data
   * @returns Rating delta
   */
  static calculateFromVote(input: VoteOutcomeInput): RatingDelta {
    const { outcome, eligibleVoterCount, voteCount, percentPositive } = input;

    // If no votes, no change
    if (voteCount === 0) {
      return RatingDelta.create(0);
    }

    // Calculate base delta from percentage
    // Positive outcome: +1 to +20
    // Negative outcome: -1 to -20
    // Tie: 0
    let baseDelta: number;

    if (outcome.outcome === 'positive') {
      baseDelta = (percentPositive / 100) * 20; // 0 to +20
    } else if (outcome.outcome === 'negative') {
      baseDelta = -((100 - percentPositive) / 100) * 20; // -20 to 0
    } else {
      baseDelta = 0; // Tie
    }

    // Weight by participation rate (higher participation = more trust in result)
    // Minimum 50% participation for full weight
    const participationRate = voteCount / eligibleVoterCount;
    const participationMultiplier = Math.max(0.5, Math.min(1, participationRate));

    const weightedDelta = baseDelta * participationMultiplier;

    // Round to 2 decimal places
    const roundedDelta = Math.round(weightedDelta * 100) / 100;

    return RatingDelta.create(roundedDelta);
  }

  /**
   * Calculate delta from system signal
   *
   * Based on section 5.2.2:
   * - ADMIN_ACTION_SLA_BONUS: +5
   * - ADMIN_ACTION_REVERSAL_PENALTY: -10 (minor) or -20 (major)
   * - ADMIN_ACTION_RULE_CLARITY_BONUS: +3
   * - ADMIN_ACTION_ABUSE_REPORT_PENALTY: -15 (minor) or -30 (major)
   *
   * @param input - System signal data
   * @returns Rating delta
   */
  static calculateFromSystemSignal(input: SystemSignalInput): RatingDelta {
    const { actionType, severity } = input;

    switch (actionType) {
      case 'sla_response':
        return RatingDelta.create(5);

      case 'reversal':
        return RatingDelta.create(severity === 'major' ? -20 : -10);

      case 'rule_clarity':
        return RatingDelta.create(3);

      case 'abuse_report':
        return RatingDelta.create(severity === 'major' ? -30 : -15);

      default:
        return RatingDelta.create(0);
    }
  }

  /**
   * Calculate combined delta from multiple vote outcomes
   * Useful for batch processing
   */
  static calculateFromMultipleVotes(inputs: VoteOutcomeInput[]): RatingDelta {
    const totalDelta = inputs.reduce((sum, input) => {
      const delta = this.calculateFromVote(input);
      return sum + delta.value;
    }, 0);

    return RatingDelta.create(totalDelta);
  }

  /**
   * Calculate combined delta from multiple system signals
   */
  static calculateFromMultipleSystemSignals(inputs: SystemSignalInput[]): RatingDelta {
    const totalDelta = inputs.reduce((sum, input) => {
      const delta = this.calculateFromSystemSignal(input);
      return sum + delta.value;
    }, 0);

    return RatingDelta.create(totalDelta);
  }

  /**
   * Calculate total delta from mixed sources
   * Combines votes and system signals
   */
  static calculateTotalDelta(
    voteInputs: VoteOutcomeInput[],
    systemInputs: SystemSignalInput[]
  ): RatingDelta {
    const voteDelta = this.calculateFromMultipleVotes(voteInputs);
    const systemDelta = this.calculateFromMultipleSystemSignals(systemInputs);

    return RatingDelta.create(voteDelta.value + systemDelta.value);
  }
}