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

import '../../../common/function/app_function.dart';
import '../../../domain/order/order.dart';
import '../../../domain/outlet/outlet.dart';
import '../../../domain/printer/printer.dart';
import '../../../presentation/components/print/print_ui.dart';

part 'printer_form_event.dart';
part 'printer_form_state.dart';
part 'printer_form_bloc.freezed.dart';

@injectable
class PrinterFormBloc extends Bloc<PrinterFormEvent, PrinterFormState> {
  final IPrinterRepository _printerRepository;
  final IOutletRepository _outletRepository;

  PrinterFormBloc(this._printerRepository, this._outletRepository)
    : super(PrinterFormState.initial()) {
    on<PrinterFormEvent>(_onPrinterFormEvent);
  }

  Future<void> _onPrinterFormEvent(
    PrinterFormEvent event,
    Emitter<PrinterFormState> emit,
  ) {
    return event.map(
      codeChanged: (e) async {
        emit(state.copyWith(code: e.code));
      },
      nameChanged: (e) async {
        emit(state.copyWith(name: e.name));
      },
      addressChanged: (e) async {
        emit(state.copyWith(address: e.address));
      },
      typeChanged: (e) async {
        emit(state.copyWith(type: e.type));
      },
      paperChanged: (e) async {
        emit(state.copyWith(paper: e.paper));
      },
      created: (e) async {
        Either<PrinterFailure, Unit> failureOrPrinter;

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

        final request = Printer(
          id: generateRandomNumber(),
          code: state.code,
          name: state.name,
          address: state.address,
          paper: state.paper,
          type: state.type,
          createdAt: DateTime.now(),
          updatedAt: DateTime.now(),
        );

        failureOrPrinter = await _printerRepository.createPrinter(request);

        emit(
          state.copyWith(
            isCreating: false,
            failureOrCreateSuccess: optionOf(failureOrPrinter),
          ),
        );
      },
      updated: (e) async {
        Either<PrinterFailure, Unit> failureOrPrinter;

        emit(state.copyWith(isUpdate: true, failureOrUpdateSuccess: none()));

        final request = Printer(
          id: generateRandomNumber(),
          code: state.code,
          name: state.name,
          address: state.address,
          paper: state.paper,
          type: state.type,
          createdAt: DateTime.now(),
          updatedAt: DateTime.now(),
        );

        failureOrPrinter = await _printerRepository.updatePrinter(
          request,
          e.id,
        );

        emit(
          state.copyWith(
            isUpdate: false,
            failureOrUpdateSuccess: optionOf(failureOrPrinter),
          ),
        );
      },
      deleted: (e) async {
        Either<PrinterFailure, Unit> failureOrPrinter;

        emit(state.copyWith(isDeleting: true, failureOrDeleteSuccess: none()));

        failureOrPrinter = await _printerRepository.deletePrinter(e.id);

        emit(
          state.copyWith(
            isDeleting: false,
            failureOrDeleteSuccess: optionOf(failureOrPrinter),
          ),
        );
      },
      printTest: (e) async {
        Either<PrinterFailure, bool> failureOrPrinter;

        emit(state.copyWith(isPrinting: true, failureOrPrintTest: none()));

        final currentOutlet = await _outletRepository.currentOutlet();

        // Ambil paper size dari DB, fallback ke state.paper jika belum tersimpan
        final savedPrinter = await _printerRepository.getPrinterByCode(e.code);
        final paper = savedPrinter.fold(
          (_) => int.tryParse(state.paper) ?? 58,
          (p) => int.tryParse(p.paper) ?? 58,
        );

        List<int> printValue = [];

        if (e.code == "receipt") {
          printValue = await PrintUi().printOrder(
            order: Order.mockOrder(),
            outlet: currentOutlet,
            cashierName: 'Kasir Test',
            paper: paper,
          );
        } else if (e.code == "checker") {
          printValue = await PrintUi().printChecker(
            order: Order.mockOrder(),
            outlet: currentOutlet,
            cashierName: 'Kasir Test',
            paper: paper,
          );
        } else if (e.code == 'kitchen') {
          printValue = await PrintUi().printKitchen(
            order: Order.mockOrder(),
            outlet: currentOutlet,
            cashierName: 'Kasir Test',
            paper: paper,
          );
        } else if (e.code == 'bar') {
          printValue = await PrintUi().printBar(
            order: Order.mockOrder(),
            outlet: currentOutlet,
            cashierName: 'Kasir Test',
            paper: paper,
          );
        } else if (e.code == 'ticket') {
          printValue = await PrintUi().printTicket(
            order: Order.mockOrder(),
            outlet: currentOutlet,
            paper: paper,
          );
        }

        final printer = Printer.fromTest(
          code: e.code,
          name: state.name,
          address: e.macAccdress,
          paper: paper.toString(),
          type: state.type,
        );

        failureOrPrinter = await _printerRepository.printStruct(
          printer,
          printValue,
        );

        emit(
          state.copyWith(
            isPrinting: false,
            failureOrPrintTest: optionOf(failureOrPrinter),
          ),
        );
      },
    );
  }
}
