import 'dart:ui';

import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';

import '../../../domain/table/table.dart';

part 'table_form_event.dart';
part 'table_form_state.dart';
part 'table_form_bloc.freezed.dart';

@injectable
class TableFormBloc extends Bloc<TableFormEvent, TableFormState> {
  final ITableRepository _repository;
  TableFormBloc(this._repository) : super(TableFormState.initial()) {
    on<TableFormEvent>(_onTableFormEvent);
  }

  Future<void> _onTableFormEvent(
    TableFormEvent event,
    Emitter<TableFormState> emit,
  ) {
    return event.map(
      nameChanged: (e) async {
        emit(state.copyWith(name: e.name));
      },
      capacityChanged: (e) async {
        emit(state.copyWith(capacity: int.tryParse(e.capacity) ?? 0));
      },
      created: (e) async {
        Either<TableFailure, Table> failureOrTable;

        emit(state.copyWith(isCreating: true, failureOrTable: none()));

        final isNameValid = state.name.isNotEmpty;
        final isCapacityValid = state.capacity > 0;

        if (isNameValid && isCapacityValid) {
          failureOrTable = await _repository.createTable(
            name: state.name,
            capacity: state.capacity,
          );

          emit(
            state.copyWith(
              failureOrTable: optionOf(failureOrTable),
              isCreating: false,
            ),
          );
        }

        emit(state.copyWith(failureOrTable: none(), isCreating: false));
      },
      updated: (e) async {
        emit(state.copyWith(isUpdating: true, failureOrTable: none()));

        await _repository.updatePosition(id: e.id, position: e.position);

        emit(
          state.copyWith(
            // failureOrTable: optionOf(failureOrTable),
            isUpdating: false,
          ),
        );
      },
      transfer: (e) async {
        Either<TableFailure, Unit> failureOrTableTransfer;

        emit(
          state.copyWith(isTransfering: true, failureOrTableTransfer: none()),
        );

        final isFromTableIdValid = e.fromTableId.isNotEmpty;
        final isToTableIdValid = e.toTableId.isNotEmpty;

        if (isFromTableIdValid && isToTableIdValid) {
          failureOrTableTransfer = await _repository.transferTable(
            fromTableId: e.fromTableId,
            toTableId: e.toTableId,
          );

          emit(
            state.copyWith(
              failureOrTableTransfer: optionOf(failureOrTableTransfer),
              isTransfering: false,
            ),
          );
        }

        emit(state.copyWith(failureOrTable: none(), isCreating: false));
      },
    );
  }
}
