import 'package:flutter/foundation.dart';
import 'package:superport_v2/core/network/failure.dart';
import 'package:superport_v2/core/common/models/paginated_result.dart';
import 'package:superport_v2/core/common/utils/pagination_utils.dart';

import '../../../../../core/permissions/permission_manager.dart';
import '../../application/permission_synchronizer.dart';
import '../../../group/domain/entities/group.dart';
import '../../../group/domain/repositories/group_repository.dart';
import '../../../menu/domain/entities/menu.dart';
import '../../../menu/domain/repositories/menu_repository.dart';
import '../../domain/entities/group_permission.dart';
import '../../domain/repositories/group_permission_repository.dart';

/// 그룹 권한 활성 여부 필터.
enum GroupPermissionStatusFilter { all, activeOnly, inactiveOnly }

/// 그룹-메뉴 권한 화면용 컨트롤러
///
/// - 목록/필터 상태를 관리하고, CRUD/복구 동작을 래핑한다.
/// - 그룹/메뉴 선택을 위해 참조 데이터를 로드한다.
class GroupPermissionController extends ChangeNotifier {
  GroupPermissionController({
    required GroupPermissionRepository permissionRepository,
    required GroupRepository groupRepository,
    required MenuRepository menuRepository,
    PermissionManager? permissionManager,
  }) : _permissionRepository = permissionRepository,
       _groupRepository = groupRepository,
       _menuRepository = menuRepository,
       _permissionManager = permissionManager;

  final GroupPermissionRepository _permissionRepository;
  final GroupRepository _groupRepository;
  final MenuRepository _menuRepository;
  final PermissionManager? _permissionManager;

  PaginatedResult<GroupPermission>? _result;
  bool _isLoading = false;
  bool _isSubmitting = false;
  bool _isLoadingGroups = false;
  bool _isLoadingMenus = false;
  String? _errorMessage;
  GroupPermissionStatusFilter _statusFilter = GroupPermissionStatusFilter.all;
  int? _groupFilter;
  int? _menuFilter;
  bool _includeDeleted = false;
  final List<Group> _groups = [];
  final List<MenuItem> _menus = [];

  PaginatedResult<GroupPermission>? get result => _result;
  bool get isLoading => _isLoading;
  bool get isSubmitting => _isSubmitting;
  bool get isLoadingGroups => _isLoadingGroups;
  bool get isLoadingMenus => _isLoadingMenus;
  String? get errorMessage => _errorMessage;
  GroupPermissionStatusFilter get statusFilter => _statusFilter;
  int? get groupFilter => _groupFilter;
  int? get menuFilter => _menuFilter;
  bool get includeDeleted => _includeDeleted;
  List<Group> get groups => List.unmodifiable(_groups);
  List<MenuItem> get menus => List.unmodifiable(_menus);

  /// 그룹 목록을 로드해 권한 연결 시 선택할 수 있도록 준비한다.
  Future<void> loadGroups() async {
    _isLoadingGroups = true;
    notifyListeners();
    try {
      final groups = await fetchAllPaginatedItems<Group>(
        request: (page, pageSize) =>
            _groupRepository.list(page: page, pageSize: pageSize),
      );
      _groups
        ..clear()
        ..addAll(groups);
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
    } finally {
      _isLoadingGroups = false;
      notifyListeners();
    }
  }

  /// 메뉴 목록을 로드해 권한 연결 시 선택할 수 있도록 준비한다.
  Future<void> loadMenus() async {
    _isLoadingMenus = true;
    notifyListeners();
    try {
      final menus = await fetchAllPaginatedItems<MenuItem>(
        request: (page, pageSize) => _menuRepository.list(
          page: page,
          pageSize: pageSize,
          includeDeleted: false,
        ),
      );
      _menus
        ..clear()
        ..addAll(menus);
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
    } finally {
      _isLoadingMenus = false;
      notifyListeners();
    }
  }

  /// 그룹 권한 목록을 조회한다.
  Future<void> fetch({int page = 1}) async {
    _isLoading = true;
    _errorMessage = null;
    notifyListeners();
    try {
      final previous = _result;
      final int resolvedPage;
      if (page < 1) {
        resolvedPage = 1;
      } else if (previous != null && previous.pageSize > 0) {
        final calculated = (previous.total / previous.pageSize).ceil();
        final maxPage = calculated < 1 ? 1 : calculated;
        resolvedPage = page > maxPage ? maxPage : page;
      } else {
        resolvedPage = page;
      }
      final isActive = switch (_statusFilter) {
        GroupPermissionStatusFilter.all => null,
        GroupPermissionStatusFilter.activeOnly => true,
        GroupPermissionStatusFilter.inactiveOnly => false,
      };
      final response = await _permissionRepository.list(
        page: resolvedPage,
        pageSize: _result?.pageSize ?? 20,
        groupId: _groupFilter,
        menuId: _menuFilter,
        isActive: isActive,
        includeDeleted: _includeDeleted,
      );
      _result = response;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  /// 그룹 필터를 변경한다.
  void updateGroupFilter(int? groupId) {
    _groupFilter = groupId;
    notifyListeners();
  }

  /// 메뉴 필터를 변경한다.
  void updateMenuFilter(int? menuId) {
    _menuFilter = menuId;
    notifyListeners();
  }

  /// 권한 활성 상태 필터를 변경한다.
  void updateStatusFilter(GroupPermissionStatusFilter filter) {
    _statusFilter = filter;
    notifyListeners();
  }

  /// 삭제 포함 여부를 변경한다.
  void updateIncludeDeleted(bool value) {
    _includeDeleted = value;
    notifyListeners();
  }

  /// 그룹 권한을 생성한다.
  Future<GroupPermission?> create(GroupPermissionInput input) async {
    _setSubmitting(true);
    try {
      final created = await _permissionRepository.create(input);
      await fetch(page: 1);
      await _syncPermissionsForGroup(input.groupId);
      return created;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
      notifyListeners();
      return null;
    } finally {
      _setSubmitting(false);
    }
  }

  /// 그룹 권한을 수정한다.
  Future<GroupPermission?> update(int id, GroupPermissionInput input) async {
    _setSubmitting(true);
    try {
      final updated = await _permissionRepository.update(id, input);
      await fetch(page: _result?.page ?? 1);
      await _syncPermissionsForGroup(input.groupId);
      return updated;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
      notifyListeners();
      return null;
    } finally {
      _setSubmitting(false);
    }
  }

  /// 그룹 권한을 삭제한다.
  Future<bool> delete(int id) async {
    _setSubmitting(true);
    try {
      final groupId = _resolveGroupIdForPermission(id);
      await _permissionRepository.delete(id);
      await fetch(page: _result?.page ?? 1);
      if (groupId != null) {
        await _syncPermissionsForGroup(groupId);
      }
      return true;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
      notifyListeners();
      return false;
    } finally {
      _setSubmitting(false);
    }
  }

  /// 삭제된 그룹 권한을 복구한다.
  Future<GroupPermission?> restore(int id) async {
    _setSubmitting(true);
    try {
      final restored = await _permissionRepository.restore(id);
      await fetch(page: _result?.page ?? 1);
      await _syncPermissionsForGroup(restored.group.id);
      return restored;
    } catch (error) {
      final failure = Failure.from(error);
      _errorMessage = failure.describe();
      notifyListeners();
      return null;
    } finally {
      _setSubmitting(false);
    }
  }

  /// 에러 메시지를 초기화한다.
  void clearError() {
    _errorMessage = null;
    notifyListeners();
  }

  /// 제출 상태 플래그를 갱신하고 리스너에게 알린다.
  void _setSubmitting(bool value) {
    _isSubmitting = value;
    notifyListeners();
  }

  Future<void> _syncPermissionsForGroup(int groupId) async {
    final manager = _permissionManager;
    if (manager == null) {
      return;
    }
    try {
      final synchronizer = PermissionSynchronizer(
        repository: _permissionRepository,
        manager: manager,
      );
      await synchronizer.syncForGroup(groupId);
    } catch (_) {
      // 권한 동기화 실패는 사용자 경험에 영향이 없도록 무시한다.
    }
  }

  int? _resolveGroupIdForPermission(int permissionId) {
    final current = _result?.items;
    if (current == null) {
      return null;
    }
    for (final item in current) {
      if (item.id == permissionId) {
        return item.group.id;
      }
    }
    return null;
  }
}
