import '../entities/approval.dart';
import '../entities/approval_flow.dart';
import '../entities/approval_template.dart';
import '../repositories/approval_repository.dart';
import '../repositories/approval_template_repository.dart';

/// 결재 템플릿을 결재 요청에 적용하는 유즈케이스.
///
/// - 템플릿 단계를 정렬해 [ApprovalStepAssignmentInput]으로 변환한 뒤 저장소에 위임한다.
class ApplyApprovalTemplateUseCase {
  ApplyApprovalTemplateUseCase({
    required ApprovalTemplateRepository templateRepository,
    required ApprovalRepository approvalRepository,
  }) : _templateRepository = templateRepository,
       _approvalRepository = approvalRepository;

  final ApprovalTemplateRepository _templateRepository;
  final ApprovalRepository _approvalRepository;

  /// [templateId]에 해당하는 템플릿을 [approvalId] 결재에 적용한다.
  ///
  /// 템플릿에 단계가 없으면 [StateError]를 던진다.
  Future<ApprovalFlow> call({
    required int approvalId,
    required int templateId,
  }) async {
    final template = await _templateRepository.fetchDetail(
      templateId,
      includeSteps: true,
    );
    if (template.steps.isEmpty) {
      throw StateError('단계가 없는 결재 템플릿은 적용할 수 없습니다.');
    }
    final steps = _mapTemplateSteps(template);
    final assignment = ApprovalStepAssignmentInput(
      approvalId: approvalId,
      steps: steps,
    );
    final approval = await _approvalRepository.assignSteps(assignment);
    return ApprovalFlow.fromApproval(approval);
  }

  List<ApprovalStepAssignmentItem> _mapTemplateSteps(
    ApprovalTemplate template,
  ) {
    final sorted = List<ApprovalTemplateStep>.of(template.steps)
      ..sort((a, b) => a.stepOrder.compareTo(b.stepOrder));
    return sorted
        .map(
          (step) => ApprovalStepAssignmentItem(
            stepOrder: step.stepOrder,
            approverId: step.approver.id,
            note: step.note,
          ),
        )
        .toList(growable: false);
  }
}
