import 'package:flutter/foundation.dart';
import 'package:superport_v2/core/network/failure.dart';

import '../../../summary/application/inventory_service.dart';
import '../../../summary/domain/entities/inventory_detail.dart';
import '../../../summary/domain/entities/inventory_filters.dart';

/// 재고 현황 단건 상태를 관리하는 컨트롤러.
class InventoryDetailController extends ChangeNotifier {
  InventoryDetailController({required InventoryService service})
    : _service = service;

  final InventoryService _service;
  final Map<int, _InventoryDetailState> _states = {};

  InventoryDetail? detailOf(int productId) => _states[productId]?.detail;

  InventoryDetailFilter filterOf(int productId) =>
      _states[productId]?.filter ?? const InventoryDetailFilter();

  bool isLoading(int productId) => _states[productId]?.isLoading ?? false;

  String? errorOf(int productId) => _states[productId]?.errorMessage;

  /// 단건 상세를 조회한다. [force]가 true면 캐시 여부와 관계없이 재조회한다.
  Future<void> fetch(
    int productId, {
    InventoryDetailFilter? filter,
    bool force = false,
  }) async {
    final current = _states[productId];
    final effectiveFilter =
        filter ?? current?.filter ?? const InventoryDetailFilter();
    if (!force &&
        current != null &&
        current.detail != null &&
        !_hasFilterChanged(current.filter, effectiveFilter) &&
        !current.isLoading &&
        current.errorMessage == null) {
      return;
    }

    _states[productId] =
        (current ?? _InventoryDetailState(filter: effectiveFilter)).copyWith(
          isLoading: true,
          errorMessage: null,
          filter: effectiveFilter,
        );
    notifyListeners();

    try {
      final detail = await _service.fetchDetail(
        productId,
        filter: effectiveFilter,
      );
      _states[productId] = _states[productId]!.copyWith(
        detail: detail,
        isLoading: false,
        errorMessage: null,
        filter: effectiveFilter,
      );
    } catch (error) {
      final failure = Failure.from(error);
      _states[productId] = _states[productId]!.copyWith(
        isLoading: false,
        errorMessage: failure.describe(),
      );
    }

    notifyListeners();
  }

  /// 이벤트 개수 제한을 변경하고 다시 조회한다.
  Future<void> updateEventLimit(int productId, int limit) {
    final current = filterOf(productId);
    final next = InventoryDetailFilter(
      warehouseId: current.warehouseId,
      eventLimit: limit,
    );
    return fetch(productId, filter: next, force: true);
  }

  /// 특정 창고 기준으로 상세를 조회한다.
  Future<void> updateWarehouseFilter(int productId, int? warehouseId) {
    final current = filterOf(productId);
    final next = InventoryDetailFilter(
      warehouseId: warehouseId,
      eventLimit: current.eventLimit,
    );
    return fetch(productId, filter: next, force: true);
  }

  void clearError(int productId) {
    final state = _states[productId];
    if (state == null || state.errorMessage == null) {
      return;
    }
    _states[productId] = state.copyWith(errorMessage: null);
    notifyListeners();
  }

  bool _hasFilterChanged(
    InventoryDetailFilter previous,
    InventoryDetailFilter next,
  ) {
    return previous.warehouseId != next.warehouseId ||
        previous.eventLimit != next.eventLimit;
  }
}

class _InventoryDetailState {
  const _InventoryDetailState({
    required this.filter,
    this.detail,
    this.isLoading = false,
    this.errorMessage,
  });

  final InventoryDetailFilter filter;
  final InventoryDetail? detail;
  final bool isLoading;
  final String? errorMessage;

  _InventoryDetailState copyWith({
    InventoryDetailFilter? filter,
    InventoryDetail? detail,
    bool? isLoading,
    String? errorMessage,
  }) {
    return _InventoryDetailState(
      filter: filter ?? this.filter,
      detail: detail ?? this.detail,
      isLoading: isLoading ?? this.isLoading,
      errorMessage: errorMessage ?? this.errorMessage,
    );
  }
}
