import 'dart:developer';

import 'package:dartz/dartz.dart';
import 'package:data_channel/data_channel.dart';
import 'package:injectable/injectable.dart';
import 'package:sqflite/sql.dart';

import '../../../common/database/database_helper.dart';
import '../../../domain/printer/printer.dart';
import '../printer_dtos.dart';

@injectable
class PrinterLocalDataProvider {
  final DatabaseHelper _databaseHelper;

  final _logName = 'PrinterLocalDataProvider';

  PrinterLocalDataProvider(this._databaseHelper);

  Future<DC<PrinterFailure, Unit>> createPrinter(PrinterDto printer) async {
    final db = await _databaseHelper.database;
    try {
      log('Creating printer: ${printer.toString()}', name: _logName);

      final printerExist = await findPrinterByCode(printer.code);

      if (printerExist.hasData) {
        return DC.error(
          const PrinterFailure.dynamicErrorMessage('Printer Telah Terdaftar'),
        );
      }

      await db.insert(
        'printers',
        printer.toMapCreating(),
        conflictAlgorithm: ConflictAlgorithm.abort,
      );

      log('Success created printer', name: _logName);

      return DC.data(unit);
    } catch (e) {
      log('Error creating printer', name: _logName, error: e);

      return DC.error(
        const PrinterFailure.dynamicErrorMessage('Error creating printer'),
      );
    }
  }

  Future<DC<PrinterFailure, Unit>> updatePrinter(
    PrinterDto printer,
    int id,
  ) async {
    final db = await _databaseHelper.database;
    try {
      log('Updating printer: ${printer.toString()}', name: _logName);

      final updatedRows = await db.update(
        'printers',
        printer.toMapForUpdate(),
        where: 'id = ?',
        whereArgs: [id],
      );

      if (updatedRows == 0) {
        return DC.error(
          const PrinterFailure.dynamicErrorMessage('Printer not found'),
        );
      }

      log('Success updated printer', name: _logName);

      return DC.data(unit);
    } catch (e) {
      log('Error updating printer', name: _logName, error: e);

      return DC.error(
        const PrinterFailure.dynamicErrorMessage('Error updating printer'),
      );
    }
  }

  Future<DC<PrinterFailure, Unit>> deletePrinter(int id) async {
    final db = await _databaseHelper.database;
    try {
      log('Updatinf printer: ${id.toString()}', name: _logName);

      final deletedRows = await db.delete(
        'printers',
        where: 'id = ?',
        whereArgs: [id],
      );

      if (deletedRows == 0) {
        return DC.error(
          const PrinterFailure.dynamicErrorMessage('Printer not found'),
        );
      }

      log('Success deleted printer', name: _logName);

      return DC.data(unit);
    } catch (e) {
      log('Error deleting printer', name: _logName, error: e);

      return DC.error(
        const PrinterFailure.dynamicErrorMessage('Error deleting printer'),
      );
    }
  }

  Future<DC<PrinterFailure, PrinterDto>> findPrinterByCode(String code) async {
    final db = await _databaseHelper.database;
    try {
      log('Getting printer by code: $code', name: _logName);

      final result = await db.query(
        'printers',
        where: 'code = ?',
        whereArgs: [code],
      );

      if (result.isEmpty) {
        log('Printer with code $code not found');
        return DC.error(const PrinterFailure.empty());
      }

      final printer = PrinterDto.fromJson(result.first);

      return DC.data(printer);
    } catch (e) {
      log('findPrinterByCode', name: _logName, error: e);

      return DC.error(
        const PrinterFailure.dynamicErrorMessage('Error getting printer'),
      );
    }
  }
}
