/**
 * Use Case: QuickPenaltyUseCase
 *
 * Allows league admins to quickly issue common penalties without protest process.
 * Designed for fast, common penalty scenarios like track limits, warnings, etc.
 */

import type { Logger } from '@core/shared/domain/Logger';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import { randomUUID } from 'crypto';
import { Penalty } from '../../domain/entities/penalty/Penalty';
import { LeagueMembershipRepository } from '../../domain/repositories/LeagueMembershipRepository';
import { PenaltyRepository } from '../../domain/repositories/PenaltyRepository';
import { RaceRepository } from '../../domain/repositories/RaceRepository';

export type QuickPenaltyErrorCode = 'RACE_NOT_FOUND' | 'UNAUTHORIZED' | 'UNKNOWN_INFRACTION' | 'REPOSITORY_ERROR';

export type QuickPenaltyApplicationError = ApplicationErrorCode<QuickPenaltyErrorCode, { message: string }>;

export type QuickPenaltyInput = {
  raceId: string;
  driverId: string;
  adminId: string;
  infractionType: 'track_limits' | 'unsafe_rejoin' | 'aggressive_driving' | 'false_start' | 'other';
  severity: 'warning' | 'minor' | 'major' | 'severe';
  notes?: string;
};

export type QuickPenaltyResult = {
  penaltyId: string;
  raceId: string;
  driverId: string;
  type: string;
  value?: number;
  reason: string;
};

export class QuickPenaltyUseCase {
  constructor(
    private readonly penaltyRepository: PenaltyRepository,
    private readonly raceRepository: RaceRepository,
    private readonly leagueMembershipRepository: LeagueMembershipRepository,
    private readonly logger: Logger,
  ) {}

  async execute(input: QuickPenaltyInput): Promise<Result<QuickPenaltyResult, QuickPenaltyApplicationError>> {
    this.logger.debug('Executing QuickPenaltyUseCase', { input });

    try {
      // Validate race exists
      const race = await this.raceRepository.findById(input.raceId);
      if (!race) {
        this.logger.warn('Race not found', { raceId: input.raceId });
        return Result.err({ code: 'RACE_NOT_FOUND', details: { message: 'Race not found' } });
      }

      // Validate admin has authority
      const memberships = await this.leagueMembershipRepository.getLeagueMembers(race.leagueId);
      const adminMembership = memberships.find(
        (m) => m.driverId.toString() === input.adminId && m.status.toString() === 'active'
      );

      if (!adminMembership || (adminMembership.role.toString() !== 'owner' && adminMembership.role.toString() !== 'admin')) {
        this.logger.warn('Unauthorized admin attempting to issue penalty', { adminId: input.adminId, leagueId: race.leagueId });
        return Result.err({ code: 'UNAUTHORIZED', details: { message: 'Only league owners and admins can issue penalties' } });
      }

      // Map infraction + severity to penalty type and value
      const penaltyMapping = this.mapInfractionToPenalty(
        input.infractionType,
        input.severity
      );

      if (!penaltyMapping) {
        this.logger.error(
          'Unknown infraction type',
          undefined,
          { infractionType: input.infractionType, severity: input.severity },
        );
        return Result.err({ code: 'UNKNOWN_INFRACTION', details: { message: 'Unknown infraction type' } });
      }

      const { type, value, reason } = penaltyMapping;

      // Create the penalty
      const penalty = Penalty.create({
        id: randomUUID(),
        leagueId: race.leagueId,
        raceId: input.raceId,
        driverId: input.driverId,
        type,
        ...(value !== undefined ? { value } : {}),
        reason,
        issuedBy: input.adminId,
        status: 'applied', // Quick penalties are applied immediately
        issuedAt: new Date(),
        appliedAt: new Date(),
        ...(input.notes !== undefined ? { notes: input.notes } : {}),
      });

      await this.penaltyRepository.create(penalty);

      const result: QuickPenaltyResult = {
        penaltyId: penalty.id.toString(),
        raceId: input.raceId,
        driverId: input.driverId,
        type,
        ...(value !== undefined ? { value } : {}),
        reason,
      };

      this.logger.info('Quick penalty applied successfully', { penaltyId: penalty.id, raceId: input.raceId, driverId: input.driverId });
      return Result.ok(result);
    } catch (error: unknown) {
      const err =
        error instanceof Error ? error : new Error('Failed to apply quick penalty');

      this.logger.error('Failed to apply quick penalty', err);

      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: { message: err.message },
      });
    }
  }

  private mapInfractionToPenalty(
    infractionType: QuickPenaltyInput['infractionType'],
    severity: QuickPenaltyInput['severity']
  ): { type: string; value?: number; reason: string } | null {
    const severityMultipliers: Record<QuickPenaltyInput['severity'], number> = {
      warning: 1,
      minor: 2,
      major: 3,
      severe: 4,
    };

    const multiplier = severityMultipliers[severity];

    switch (infractionType) {
      case 'track_limits':
        if (severity === 'warning') {
          return { type: 'warning', reason: 'Track limits violation - warning' };
        }
        return {
          type: 'points_deduction',
          value: multiplier,
          reason: `Track limits violation - ${multiplier} point${multiplier > 1 ? 's' : ''} deducted`
        };

      case 'unsafe_rejoin':
        return {
          type: 'time_penalty',
          value: 5 * multiplier,
          reason: `Unsafe rejoining to track - +${5 * multiplier}s time penalty`
        };

      case 'aggressive_driving':
        if (severity === 'warning') {
          return { type: 'warning', reason: 'Aggressive driving - warning' };
        }
        return {
          type: 'points_deduction',
          value: 2 * multiplier,
          reason: `Aggressive driving - ${2 * multiplier} point${multiplier > 1 ? 's' : ''} deducted`
        };

      case 'false_start':
        return {
          type: 'grid_penalty',
          value: multiplier,
          reason: `False start - ${multiplier} grid position${multiplier > 1 ? 's' : ''} penalty`
        };

      case 'other':
        if (severity === 'warning') {
          return { type: 'warning', reason: 'General infraction - warning' };
        }
        return {
          type: 'points_deduction',
          value: 3 * multiplier,
          reason: `General infraction - ${3 * multiplier} point${multiplier > 1 ? 's' : ''} deducted`
        };

      default:
        return null;
    }
  }
}