import 'dart:convert';

import 'package:logger/logger.dart';
import 'package:meta/meta.dart';
import 'package:redux/redux.dart';
import 'package:redux_thunk/redux_thunk.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/entity/transaction_entity.dart';
import 'package:satu/core/models/flow/product_dao.dart';
import 'package:satu/core/models/flow/transaction_state.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/services/db_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/core/utils/logger.dart';
import 'package:uuid/uuid.dart';

import '../store.dart';

@immutable
class SetSellStateAction {
  final SellState sellState;

  SetSellStateAction(this.sellState);
}

final Logger log = getLogger('SetSellStateAction');

final DbService _dbService = locator<DbService>();

ThunkAction<AppState> counterOrEditSellItem(
    {required int transactionId, required double counter, double? price}) {
  return (Store<AppState> store) async {
    log.i('counterSellItem');
    int? appCompanyId = store.state.userState!.auth!.companyId;
    String? uuid = store.state.sellState!.transactionState!.uuid;

    Transaction? transaction;

    if (uuid != null) {
      final List<Map<String, dynamic>> set =
          await _dbService.queryRowsWithWhere(
              transactionTableName,
              '$transactionColumnAppCompanyId = ? '
              ' and $transactionColumnStatus = ? '
              ' and $transactionColumnType = ? '
              ' and $transactionColumnId = ?',
              [
                appCompanyId,
                transactionStatusPrepare,
                transactionTypeSell,
                transactionId
              ],
              orderBy: '$transactionColumnCreatedAt desc');
      if (set.isNotEmpty) {
        transaction = Transaction.fromMap(set.first);
      }
    }
    if (transaction != null) {
      final ProductDao item = ProductDao.fromMap(jsonDecode(transaction.data!));
      if (price != null) {
        item.price = price;
        item.count = counter;
      } else {
        final String val = ((item.count ?? 0) + counter).toStringAsFixed(5);
        item.count = num.parse(val);
      }
      transaction.data = jsonEncode(item.toMap());
      _dbService.update(transactionTableName, transaction.toMap());
    }
    // refresh from db ? after save data
    await loadSellData(store);
  };
}

ThunkAction<AppState> addSellItem({required Good good, String? excise}) {
  return (Store<AppState> store) async {
    log.i('addSellItem');
    final int? appCompanyId = store.state.userState!.auth!.companyId;
    String? uuid = store.state.sellState!.transactionState!.uuid;

    Transaction? transaction;

    if (uuid != null) {
      List<Map<String, dynamic>> set = await _dbService.queryRowsWithWhere(
          transactionTableName,
          '$transactionColumnAppCompanyId = ? '
              ' and $transactionColumnStatus = ? '
              ' and $transactionColumnType = ?',
          [appCompanyId, transactionStatusPrepare, transactionTypeSell],
          orderBy: '$transactionColumnCreatedAt desc');
      if (set.isNotEmpty) {
        for (Map<String, dynamic> map in set) {
          Transaction _transaction = Transaction.fromMap(map);
          ProductDao _product =
              ProductDao.fromMap(jsonDecode(_transaction.data!));
          if (_product.id == good.id && _product.excise == excise) {
            transaction = _transaction;
            break;
          }
        }
      }
    }

    if (transaction != null) {
      ProductDao item = ProductDao.fromMap(jsonDecode(transaction.data!));
      item..count = item.count! + 1;
      transaction.data = jsonEncode(item.toMap());
      transaction.createdAt = DateTime.now().toIso8601String();
      _dbService.update(transactionTableName, transaction.toMap());
    } else {
      ProductDao item = new ProductDao()
        ..id = good.id
        ..price = good.price
        ..article = good.articul
        ..count = 1.0
        ..eanCode = good.ean
        ..productName = good.name
        ..excise = excise;
      //category add logic
      if (good.categoryId != null) {
        List<Map<String, dynamic>> set = await _dbService
            .queryRowsWithWhere(categoryTableName, 'id = ?', [good.categoryId]);
        if (set.isNotEmpty) {
          Category category = Category.fromMap(set.first);
          item.categoryId = category.id;
          item.categoryName = category.name;
        }
      }

      if (uuid == null) {
        var uuidTool = Uuid();
        ;
        uuid = uuidTool.v4();
      }

      transaction = new Transaction()
        ..uuid = uuid
        ..status = transactionStatusPrepare
        ..appCompanyId = appCompanyId
        ..type = transactionTypeSell
        ..createdAt = DateTime.now().toIso8601String()
        ..data = jsonEncode(item.toMap());
      await _dbService.insert(transactionTableName, transaction.toMap());
    }
    // refresh from db ? after save data
    await loadSellData(store);
  };
}

ThunkAction<AppState> removeSellItem({required int transactionId}) {
  return (Store<AppState> store) async {
    int? appCompanyId = store.state.userState!.auth!.companyId;
    String? uuid = store.state.sellState!.transactionState!.uuid;

    int count = await _dbService.delete(transactionTableName, transactionId);
    log.i('removeSellItem ${count} by transactionId:${transactionId}');

    // refresh from db ? after save data
    await loadSellData(store);
  };
}

Future<void> removeAllSellData(Store<AppState> store) async {
  try {
    log.i('removeAllSellData');
    int? appCompanyId = store.state.userState!.auth!.companyId;
    String? uuid = store.state.sellState!.transactionState!.uuid;
    await _dbService.deleteByWhere(
        transactionTableName,
        '$transactionColumnAppCompanyId = ? '
        ' and $transactionColumnStatus = ? '
        ' and ${transactionColumnType} = ?'
        ' and ${transactionColumnUuid} = ?',
        [appCompanyId, transactionStatusPrepare, transactionTypeSell, uuid]);
    await loadSellData(store);
  } catch (e, stack) {
    log.e('removeAllSellData', e, stack);
  }
}

Future<void> loadSellData(Store<AppState> store) async {
  try {
    log.i('loadSellData');
    int? appCompanyId = store.state.userState!.auth!.companyId;
    List<Map<String, dynamic>> set = await _dbService.queryRowsWithWhere(
        transactionTableName,
        '$transactionColumnAppCompanyId = ? and $transactionColumnStatus = ? and ${transactionColumnType} = ?',
        [appCompanyId, transactionStatusPrepare, transactionTypeSell],
        orderBy: '$transactionColumnCreatedAt desc');
    List<ProductDao> list = [];
    String? uuid;
    for (Map<String, dynamic> map in set) {
      Transaction transaction = Transaction.fromMap(map);
      uuid = transaction.uuid;
      ProductDao productDao = ProductDao.fromMap(jsonDecode(transaction.data!));
      productDao.transactionId = transaction.id;
      list.add(productDao);
    }
    store.dispatch(SetSellStateAction(SellState(
        items: list, transactionState: TransactionState()..uuid = uuid)));
  } catch (e, stack) {
    log.e('loadSellData', e, stack);
  }
}
