import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
import type { SeasonStatus } from '../../domain/value-objects/SeasonStatus';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { UseCaseOutputPort } from '@core/shared/application';

export type SeasonLifecycleTransition =
  | 'activate'
  | 'complete'
  | 'archive'
  | 'cancel';

export type ManageSeasonLifecycleInput = {
  leagueId: string;
  seasonId: string;
  transition: SeasonLifecycleTransition;
};

export type ManagedSeasonState = {
  id: string;
  leagueId: string;
  status: SeasonStatus;
  startDate?: Date;
  endDate?: Date;
};

export type ManageSeasonLifecycleResult = {
  season: ManagedSeasonState;
};

export type ManageSeasonLifecycleErrorCode =
  | 'LEAGUE_NOT_FOUND'
  | 'SEASON_NOT_FOUND'
  | 'INVALID_TRANSITION'
  | 'REPOSITORY_ERROR';

/**
 * ManageSeasonLifecycleUseCase
 */
export class ManageSeasonLifecycleUseCase {
  constructor(
    private readonly leagueRepository: ILeagueRepository,
    private readonly seasonRepository: ISeasonRepository,
    private readonly output: UseCaseOutputPort<ManageSeasonLifecycleResult>,
  ) {}

  async execute(
    input: ManageSeasonLifecycleInput,
  ): Promise<Result<void, ApplicationErrorCode<ManageSeasonLifecycleErrorCode, { 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: ${input.leagueId}` },
        });
      }

      const season = await this.seasonRepository.findById(input.seasonId);
      if (!season || season.leagueId !== league.id.toString()) {
        return Result.err({
          code: 'SEASON_NOT_FOUND',
          details: {
            message: `Season ${input.seasonId} does not belong to league ${league.id.toString()}`,
          },
        });
      }

      let updated;
      try {
        switch (input.transition) {
          case 'activate':
            updated = season.activate();
            break;
          case 'complete':
            updated = season.complete();
            break;
          case 'archive':
            updated = season.archive();
            break;
          case 'cancel':
            updated = season.cancel();
            break;
          default:
            throw new Error('Unsupported Season lifecycle transition');
        }
      } catch (error) {
        return Result.err({
          code: 'INVALID_TRANSITION',
          details: { message: `Invalid transition: ${(error as Error).message}` },
        });
      }

      await this.seasonRepository.update(updated);

      const result: ManageSeasonLifecycleResult = {
        season: {
          id: updated.id,
          leagueId: updated.leagueId,
          status: updated.status,
          ...(updated.startDate !== undefined ? { startDate: updated.startDate } : {}),
          ...(updated.endDate !== undefined ? { endDate: updated.endDate } : {}),
        },
      };

      this.output.present(result);

      return Result.ok(undefined);
    } catch (error) {
      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: {
          message: (error as Error).message || 'Failed to manage season lifecycle',
        },
      });
    }
  }
}