/**
 * Application Use Case: SubmitProtestDefenseUseCase
 *
 * Allows the accused driver to submit their defense statement for a protest.
 */

import { Logger } from '@core/shared/domain/Logger';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { LeagueRepository } from '../../domain/repositories/LeagueRepository';
import type { ProtestRepository } from '../../domain/repositories/ProtestRepository';

export type SubmitProtestDefenseInput = {
  leagueId: string;
  protestId: string;
  driverId: string;
  defenseText: string;
  videoUrl?: string;
};

export type SubmitProtestDefenseResult = {
  leagueId: string;
  protestId: string;
  driverId: string;
  status: 'defense_submitted';
};

export type SubmitProtestDefenseErrorCode =
  | 'LEAGUE_NOT_FOUND'
  | 'PROTEST_NOT_FOUND'
  | 'DRIVER_NOT_ALLOWED'
  | 'INVALID_PROTEST_STATE'
  | 'REPOSITORY_ERROR';

export class SubmitProtestDefenseUseCase {
  constructor(private readonly leagueRepository: LeagueRepository,
    private readonly protestRepository: ProtestRepository,
    private readonly logger: Logger) {}

  async execute(
    input: SubmitProtestDefenseInput,
  ): Promise<Result<SubmitProtestDefenseResult, ApplicationErrorCode<SubmitProtestDefenseErrorCode, { message: string }>>> {
    try {
      const league = await this.leagueRepository.findById(input.leagueId);
      if (!league) {
        return Result.err({
          code: 'LEAGUE_NOT_FOUND',
          details: { message: 'League not found' },
        });
      }

      const protest = await this.protestRepository.findById(input.protestId);
      if (!protest) {
        return Result.err({
          code: 'PROTEST_NOT_FOUND',
          details: { message: 'Protest not found' },
        });
      }

      if (protest.accusedDriverId !== input.driverId) {
        return Result.err({
          code: 'DRIVER_NOT_ALLOWED',
          details: { message: 'Driver is not allowed to submit a defense for this protest' },
        });
      }

      if (!protest.canSubmitDefense()) {
        return Result.err({
          code: 'INVALID_PROTEST_STATE',
          details: { message: 'Defense cannot be submitted for this protest' },
        });
      }

      const updatedProtest = protest.submitDefense(input.defenseText, input.videoUrl);
      await this.protestRepository.update(updatedProtest);

      const result: SubmitProtestDefenseResult = {
        leagueId: input.leagueId,
        protestId: protest.id,
        driverId: input.driverId,
        status: 'defense_submitted',
      };

      return Result.ok(result);
    } catch (error: unknown) {
      const message =
        error instanceof Error && typeof error.message === 'string'
          ? error.message
          : 'Failed to submit protest defense';

      this.logger.error(
        'SubmitProtestDefenseUseCase.execute failed',
        error instanceof Error ? error : undefined,
      );

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