import 'package:superport_v2/core/permissions/permission_manager.dart';

import '../../features/auth/domain/entities/auth_session.dart';
import '../../features/masters/group/domain/entities/group.dart';
import '../../features/masters/group/domain/repositories/group_repository.dart';
import '../../features/masters/group_permission/application/permission_synchronizer.dart';
import '../../features/masters/group_permission/domain/repositories/group_permission_repository.dart';

/// 세션 정보와 그룹 권한을 기반으로 [PermissionManager]를 초기화하는 부트스트랩 도우미.
class PermissionBootstrapper {
  PermissionBootstrapper({
    required PermissionManager manager,
    required GroupRepository groupRepository,
    required GroupPermissionRepository groupPermissionRepository,
  }) : _manager = manager,
       _groupRepository = groupRepository,
       _groupPermissionRepository = groupPermissionRepository;

  final PermissionManager _manager;
  final GroupRepository _groupRepository;
  final GroupPermissionRepository _groupPermissionRepository;

  /// 세션의 권한 목록과 그룹 권한을 적용한다.
  Future<void> apply(AuthSession session) async {
    _manager.clearServerPermissions();

    final aggregated = <String, Set<PermissionAction>>{};
    var hasMenuPermission = false;

    void merge(Map<String, Set<PermissionAction>> map) {
      if (map.isEmpty) {
        return;
      }
      for (final entry in map.entries) {
        final target = aggregated.putIfAbsent(
          entry.key,
          () => <PermissionAction>{},
        );
        target.addAll(entry.value);
        if (!entry.key.startsWith('scope:')) {
          hasMenuPermission = true;
        }
      }
    }

    for (final permission in session.permissions) {
      merge(permission.toPermissionMap());
    }

    if (!hasMenuPermission) {
      final map = await _loadGroupPermissions(
        groupId: session.user.primaryGroupId,
      );
      merge(map);
    }

    if (aggregated.isNotEmpty) {
      _manager.applyServerPermissions(aggregated);
      return;
    }

    await _synchronizePermissions(groupId: session.user.primaryGroupId);
  }

  Future<void> _synchronizePermissions({int? groupId}) async {
    final targetGroupId = await _resolveGroupId(groupId);
    if (targetGroupId == null) {
      return;
    }

    final synchronizer = PermissionSynchronizer(
      repository: _groupPermissionRepository,
      manager: _manager,
    );
    await synchronizer.syncForGroup(targetGroupId);
  }

  Future<Map<String, Set<PermissionAction>>> _loadGroupPermissions({
    int? groupId,
  }) async {
    final targetGroupId = await _resolveGroupId(groupId);
    if (targetGroupId == null) {
      return const {};
    }
    final synchronizer = PermissionSynchronizer(
      repository: _groupPermissionRepository,
      manager: _manager,
    );
    return synchronizer.fetchPermissionMap(targetGroupId);
  }

  Future<int?> _resolveGroupId(int? groupId) async {
    if (groupId != null) {
      return groupId;
    }
    final defaultGroups = await _groupRepository.list(
      page: 1,
      pageSize: 1,
      isDefault: true,
    );
    var targetGroup = _firstGroupWithId(defaultGroups.items);

    if (targetGroup == null) {
      final fallbackGroups = await _groupRepository.list(page: 1, pageSize: 1);
      targetGroup = _firstGroupWithId(fallbackGroups.items);
    }
    return targetGroup?.id;
  }

  Group? _firstGroupWithId(List<Group> groups) {
    for (final group in groups) {
      if (group.id != null) {
        return group;
      }
    }
    return null;
  }
}
