import 'package:hooks_riverpod/hooks_riverpod.dart';

import '../../../common/domain/metal_type.dart';
import '../data/market_models.dart';
import '../data/mock_market_repository.dart';
import 'market_controller.dart';

final exchangeCalculatorControllerProvider =
    StateNotifierProvider<
      ExchangeCalculatorController,
      ExchangeCalculatorState
    >((ref) {
      final market = ref.watch(marketControllerProvider);
      final repository = ref.watch(mockMarketRepositoryProvider);
      return ExchangeCalculatorController(
        repository: repository,
        initialMetal: market.selectedMetal,
      );
    });

class ExchangeCalculatorState {
  const ExchangeCalculatorState({
    required this.metal,
    required this.channels,
    required this.selectedChannel,
    required this.gram,
    required this.amount,
    required this.swapped,
  });

  final MetalType metal;
  final List<ExchangeChannel> channels;
  final ExchangeChannel selectedChannel;
  final double gram;
  final double amount;
  final bool swapped;

  ExchangeCalculatorState copyWith({
    MetalType? metal,
    List<ExchangeChannel>? channels,
    ExchangeChannel? selectedChannel,
    double? gram,
    double? amount,
    bool? swapped,
  }) {
    return ExchangeCalculatorState(
      metal: metal ?? this.metal,
      channels: channels ?? this.channels,
      selectedChannel: selectedChannel ?? this.selectedChannel,
      gram: gram ?? this.gram,
      amount: amount ?? this.amount,
      swapped: swapped ?? this.swapped,
    );
  }
}

class ExchangeCalculatorController
    extends StateNotifier<ExchangeCalculatorState> {
  ExchangeCalculatorController({
    required MockMarketRepository repository,
    required MetalType initialMetal,
  }) : _repository = repository,
       super(_initialState(repository, initialMetal));

  final MockMarketRepository _repository;

  void selectMetal(MetalType metal) {
    final channels = _repository.channelsFor(metal);
    final selected = channels.first;
    state = state.copyWith(
      metal: metal,
      channels: channels,
      selectedChannel: selected,
      amount: state.gram * selected.pricePerGram,
    );
  }

  void selectChannel(String channelId) {
    final selected = state.channels.firstWhere(
      (channel) => channel.id == channelId,
      orElse: () => state.channels.first,
    );
    state = state.copyWith(
      selectedChannel: selected,
      amount: state.gram * selected.pricePerGram,
    );
  }

  void setGram(double gram) {
    state = state.copyWith(
      gram: gram,
      amount: gram * state.selectedChannel.pricePerGram,
    );
  }

  void setAmount(double amount) {
    state = state.copyWith(
      amount: amount,
      gram: amount / state.selectedChannel.pricePerGram,
    );
  }

  void toggleSwapped() {
    state = state.copyWith(swapped: !state.swapped);
  }

  static ExchangeCalculatorState _initialState(
    MockMarketRepository repository,
    MetalType metal,
  ) {
    final channels = repository.channelsFor(metal);
    final selected = channels.first;
    const gram = 50.0;
    return ExchangeCalculatorState(
      metal: metal,
      channels: channels,
      selectedChannel: selected,
      gram: gram,
      amount: gram * selected.pricePerGram,
      swapped: false,
    );
  }
}
