119 lines
3.4 KiB
TypeScript
119 lines
3.4 KiB
TypeScript
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
|
|
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
|
|
import type { SeasonStatus } from '../../domain/entities/season/Season';
|
|
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',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
} |