import 'dart:async';

import 'package:get_it/get_it.dart';

import '../../../domain/entities/approval.dart';
import '../../../shared/domain/repositories/approval_approver_repository.dart';
import '../controllers/approval_request_controller.dart';
import '../../../../inventory/transactions/domain/entities/stock_transaction_input.dart';

/// 재고 전표 결재 섹션에서 공통으로 사용하는 초기화 유틸리티.
///
/// - 기존 결재 정보 또는 저장된 초안을 기반으로 단계/상신자를 세팅한다.
class ApprovalFormInitializer {
  ApprovalFormInitializer._();

  /// 결재 구성 컨트롤러에 기본값을 주입한다.
  static Future<void> populate({
    required ApprovalRequestController controller,
    Approval? existingApproval,
    StockTransactionApprovalInput? draft,
    ApprovalRequestParticipant? defaultRequester,
    ApprovalApproverRepository? repository,
  }) async {
    if (existingApproval != null) {
      _applyExistingApproval(controller, existingApproval);
      return;
    }
    if (defaultRequester != null) {
      controller.setRequester(defaultRequester);
    }
    if (draft != null) {
      await _applyDraft(controller, draft, repository ?? _resolveRepository());
    }
  }

  static void _applyExistingApproval(
    ApprovalRequestController controller,
    Approval approval,
  ) {
    controller.setRequester(
      ApprovalRequestParticipant(
        id: approval.requester.id,
        name: approval.requester.name,
        employeeNo: approval.requester.employeeNo,
      ),
    );
    final steps = approval.steps
        .map(
          (step) => ApprovalRequestStep(
            stepOrder: step.stepOrder,
            approver: ApprovalRequestParticipant(
              id: step.approver.id,
              name: step.approver.name,
              employeeNo: step.approver.employeeNo,
            ),
            note: step.note,
          ),
        )
        .toList(growable: false);
    if (steps.isNotEmpty) {
      controller.applyTemplateSteps(steps);
    }
  }

  static Future<void> _applyDraft(
    ApprovalRequestController controller,
    StockTransactionApprovalInput draft,
    ApprovalApproverRepository? repository,
  ) async {
    final repo = repository;
    if (repo == null) {
      return;
    }

    final requester = await _fetchParticipant(repo, draft.requestedById);
    if (requester != null) {
      controller.setRequester(requester);
    }

    final futures = draft.steps
        .map((step) async {
          final participant = await _fetchParticipant(repo, step.approverId);
          if (participant == null) {
            return null;
          }
          return ApprovalRequestStep(
            stepOrder: step.stepOrder,
            approver: participant,
            note: step.note,
          );
        })
        .toList(growable: false);

    final resolvedSteps = await Future.wait(futures);
    final steps = resolvedSteps.whereType<ApprovalRequestStep>().toList();
    if (steps.isNotEmpty) {
      controller.applyTemplateSteps(steps);
    }
  }

  static Future<ApprovalRequestParticipant?> _fetchParticipant(
    ApprovalApproverRepository repository,
    int id,
  ) async {
    final candidate = await repository.fetchById(id);
    if (candidate == null) {
      return null;
    }
    return ApprovalRequestParticipant(
      id: candidate.id,
      name: candidate.name,
      employeeNo: candidate.employeeNo,
    );
  }

  static ApprovalApproverRepository? _resolveRepository() {
    final getIt = GetIt.I;
    if (!getIt.isRegistered<ApprovalApproverRepository>()) {
      return null;
    }
    return getIt<ApprovalApproverRepository>();
  }
}
