import 'dart:convert';

import 'package:satu/core/base/base_service.dart';
import 'package:satu/core/entity/transaction_entity.dart';
import 'package:satu/core/models/entity_data/transaction_data.dart';
import 'package:satu/core/models/flow/items_bean.dart';
import 'package:satu/core/models/flow/operator_bean.dart';
import 'package:satu/core/models/flow/dao/product_dao.dart';
import 'package:satu/core/models/flow/sell_request.dart';
import 'package:satu/core/models/flow/sell_response.dart';
import 'package:satu/core/models/flow/sell_return/sell_return_request.dart';
import 'package:satu/core/models/flow/transaction_state.dart';
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:uuid/uuid.dart';

import 'api_service.dart';
import 'db_service.dart';
import 'dialog_service.dart';

class DataService extends BaseService {
  final ApiService _api = locator<ApiService>();
  final DbService _db = locator<DbService>();

  final DialogService _dialogService = locator<DialogService>();

  Future<int?> sellBtnHandler(
      {double card = 0, double nal = 0, double total = 0}) async {
    final SellRequest request = SellRequest();
    final SellState sellState = Redux.store!.state.sellState!;
    final TransactionState transactionState = sellState.transactionState!;
    final List<ProductDao> items = sellState.items!;
    for (final ProductDao item in items) {
      request.items.add(_productToItemBean(item));
    }
    request.card = card;
    request.nal = nal;
    request.invoiceId = transactionState.uuid;
    request.section = transactionState.sectionName;
    request.contragent = transactionState.contragentName;
    final OperatorBean operator = OperatorBean()
      ..name = 'operator'
      ..code = 1;
    request.operator = operator;
    final SellResponse response = await _api.sell(request);
    if (response.operation == false) {
      _dialogService.showDialog(description: response.message);
      return null;
    }
    final int? transactionId = await _updateTransaction(
        transactionState: transactionState,
        total: total,
        card: card,
        nal: nal,
        sellResponse: response);

    await Redux.store!.dispatch(loadSellData);
    return transactionId;
  }

  Future<int?> returnBtnHandler({required int trId}) async {
    Map<String, dynamic>? map = await _db.queryById(transactionTableName, trId);
    if (map != null) {
      final Transaction transaction = Transaction.fromMap(map);
      final String? data = transaction.data;
      if (data != null) {
        TransactionData transactionData =
            TransactionData.fromMap(jsonDecode(data));

        const uuidTool = Uuid();
        final String uuid = uuidTool.v4();

        final SellReturnRequest request = SellReturnRequest(
          journal_id: transactionData.sellResponse!.journalId!,
          invoice_id: uuid,
        );
        final SellResponse response = await _api.sellReturn(request);
        if (response.operation == false) {
          _dialogService.showDialog(description: response.message);
          return null;
        }
        final int? appCompanyId = Redux.store!.state.userState!.auth!.companyId;
        final int? transactionId = await _addTransaction(
          uuid: uuid,
          contragentName: transactionData.contragentName,
          type: transactionTypeReturnSell,
          status: transactionStatusFinish,
          appCompanyId: appCompanyId!,
          total: transactionData.total,
          card: transactionData.card,
          nal: transactionData.nal,
          sellResponse: response,
        );

        await Redux.store!.dispatch(loadSellData);
        return transactionId;
      }
    }

    return null;
  }

  Future<int?> _updateTransaction({
    required TransactionState transactionState,
    required double card,
    required double nal,
    required double total,
    SellResponse? sellResponse,
  }) async {
    final Map<String, dynamic>? map = await _db.queryById(
        transactionTableName, transactionState.uuid,
        idColumnName: transactionColumnUuid);

    final DateTime now = DateTime.now();
    final Transaction transaction = Transaction.fromMap(map!);
    final TransactionData data =
        TransactionData.fromMap(jsonDecode(transaction.data!));
    transaction.status = transactionStatusFinish;
    transaction.updatedAt = now.toIso8601String();
    data.sellResponse = sellResponse;
    data.contragentName = transactionState.contragentName ?? '';
    data.card = card;
    data.nal = nal;
    data.total = total;
    transaction.data = jsonEncode(data.toMap());
    log.i(jsonEncode(data.toMap()));
    await _db.update(transactionTableName, transaction.toMap());
    return transaction.id;
  }

  Future<int?> _addTransaction({
    required String uuid,
    required double card,
    required double nal,
    required double total,
    required int type,
    required int status,
    required int appCompanyId,
    SellResponse? sellResponse,
    String? contragentName,
  }) async {
    final DateTime now = DateTime.now();
    final Transaction transaction = Transaction();
    final TransactionData data = TransactionData();
    transaction.status = transactionStatusFinish;
    transaction.updatedAt = now.toIso8601String();
    transaction.createdAt = now.toIso8601String();
    transaction.appCompanyId = appCompanyId;
    transaction.type = type;
    transaction.status = status;
    transaction.uuid = uuid;
    data.sellResponse = sellResponse;
    data.contragentName = contragentName ?? '';
    data.card = card;
    data.nal = nal;
    data.total = total;
    transaction.data = jsonEncode(data.toMap());
    log.i(jsonEncode(data.toMap()));
    return await _db.insert(transactionTableName, transaction.toMap());
  }

  ItemBean _productToItemBean(ProductDao product) {
    final ItemBean item = ItemBean()
      ..id = product.id
      ..price = product.price
      ..cnt = product.count
      ..name = product.productName
      ..excise = product.excise
      ..articul = product.article?.toString();
    return item;
  }

  Future<TransactionData?> getTransactionDataById(int? id) async {
    if (id == null) return null;
    try {
      Transaction? transaction = await getTransactionById(id);
      if (transaction != null) {
        final String? data = transaction.data;
        if (data != null) {
          return TransactionData.fromMap(jsonDecode(data));
        }
      }
    } catch (e, stack) {
      log.e('getTransactionDataById', e, stack);
    }
    return null;
  }

  Future<Transaction?> getTransactionById(int? id) async {
    if (id == null) return null;
    try {
      Map<String, dynamic>? map = await _db.queryById(transactionTableName, id);
      if (map != null) {
        final Transaction transaction = Transaction.fromMap(map);
        return transaction;
      }
    } catch (e, stack) {
      log.e('getTransactionById', e, stack);
    }
    return null;
  }

}
