import 'package:satu/core/base/base_service.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/models/dictionary/category/category_response.dart';
import 'package:satu/core/models/dictionary/contragent/contragent_response_entity.dart';
import 'package:satu/core/models/dictionary/good/good_response_entity.dart';
import 'package:satu/core/models/response/response_entity.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/utils/locator.dart';

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

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

  Good goodResponseToGood(GoodResponseEntity response) {
    return Good()
      ..id = response.id
      ..name = response.name
      ..basePrice = response.basePrice
      ..optPrice = response.optPrice
      ..price = response.price
      ..articul = response.articul
      ..categoryId = response.categoryId
      ..categoryName = response.categoryName
      ..divisible = response.divisible
      ..ean = response.ean13
      ..appCompanyId = response.appCompanyId;
  }

  Category categoryResponseToCategory(CategoryResponse response) {
    return Category()
      ..id = response.id
      ..parentId = response.parentId
      ..name = response.name;
  }

  Future<void> refreshFull() async {}

  Future<List<Category>> getCategoryByParentId(int? parentId) async {
    final List<Category> list = [];
    try {
      dynamic filter = {'col': 'parent_id', 'action': 'equal', 'val': parentId};
      List<CategoryResponse> responses =
          await getCategories(page: 1, perpage: 100, filter: filter);
      for (final CategoryResponse response in responses) {
        final Category category = categoryResponseToCategory(response);
        list.add(category);
      }
    } catch (e, stack) {
      log.e('getCategories', e, stack);
    }
    return list;
  }

  Future<Category?> getCategoryById(int id) async {
    Category? result;
    try {
      final int? appCompanyId = Redux.store?.state.userState?.auth?.companyId;
      final List<Map<String, dynamic>> elements = await _db.queryRowsWithWhere(
          categoryTableName,
          '$categoryColumnAppCompanyId = ? and $categoryColumnId = ?',
          [appCompanyId, id]);

      for (final Map<String, dynamic> element in elements) {
        result = Category.fromMap(element);
      }
    } catch (e, stack) {
      log.e('getCategoryById', e, stack);
    }
    return result;
  }

  Future<List<Good>> getGoodsByCategoryId(int? categoryId) async {
    final List<Good> list = [];
    try {
      dynamic filter = {
        'col': 'eacc_good_category_id',
        'action': 'equal',
        'val': categoryId
      };
      List<GoodResponseEntity> responses =
          await getGoods(page: 1, perpage: 100, filter: filter);
      for (final GoodResponseEntity response in responses) {
        final Good good = goodResponseToGood(response);
        list.add(good);
      }
    } catch (e, stack) {
      log.e('getGoods', e, stack);
    }
    return list;
  }

  Future<List<Good>> getGoodsByNameOrEan(String query) async {
    final List<Good> list = [];
    try {
      final int? appCompanyId = Redux.store?.state.userState?.auth?.companyId;
      String where =
          '( $GoodColumnAppCompanyId = ? and $GoodColumnName like ? ) ';
      final List args = [appCompanyId, '%$query%'];
      if (_isNumericInt(query) && query.length >= 8) {
        where += ' or $GoodColumnEan like ?';
        args.add('${int.parse(query).toString()}%');
      }
      final List<Map<String, dynamic>> elements =
          await _db.queryRowsWithWhere(goodTableName, where, args);
      for (final Map<String, dynamic> element in elements) {
        list.add(Good.fromMap(element));
      }
    } catch (e, stack) {
      log.e('getGoodsByCategoryId', e, stack);
    }
    return list;
  }

  bool _isNumericInt(String? str) {
    if (str == null) {
      return false;
    }
    return int.tryParse(str) != null;
  }

  Future<List<CategoryResponse>> getCategories(
      {required int page, required int perpage, dynamic filter}) async {
    List<CategoryResponse> list = [];
    try {
      final Map<String, dynamic> requestBody = <String, dynamic>{
        'page': page,
        'perpage': perpage,
        'filter': [filter]
      };

      ResponseEntity categories = await _api
          .postRequest('/goods_categories_get', requestBody: requestBody);
      if (categories.original.data != null &&
          categories.original.data!.isNotEmpty) {
        for (final dynamic map in categories.original.data!) {
          final CategoryResponse good = CategoryResponse.fromJson(map);
          list.add(good);
        }
      }
    } catch (e, stack) {
      log.e('getCategories', e, stack);
    }
    return list;
  }

  Future<String?> saveCategory(CategoryResponse category) async {
    ResponseEntity? status;
    log.i(category.toJson());
    if (category.id != null) {
      status = await _api.dictionarySave(
          '/goods_categories_edit', category.toJson());
    } else {
      status =
          await _api.dictionarySave('/goods_categories_add', category.toJson());
    }
    String? message = getErrorMsg(status);

    return message;
  }

  Future<String?> deleteCategory(CategoryResponse category) async {
    ResponseEntity status = await _api.dictionarySave(
        '/goods_categories_delete', category.toJson());
    String? message = getErrorMsg(status);
    return message;
  }

  Future<List<GoodResponseEntity>> getGoods(
      {required int page, required int perpage, dynamic filter}) async {
    List<GoodResponseEntity> list = [];
    try {
      final Map<String, dynamic> requestBody = <String, dynamic>{
        'page': page,
        'perpage': perpage,
        'filter': [filter]
      };

      ResponseEntity categories =
          await _api.postRequest('/goods_goods_get', requestBody: requestBody);
      if (categories.original.data != null &&
          categories.original.data!.isNotEmpty) {
        for (final dynamic map in categories.original.data!) {
          final GoodResponseEntity good = GoodResponseEntity.fromJson(map);
          list.add(good);
        }
      }
    } catch (e, stack) {
      log.e('getGoods', e, stack);
    }
    return list;
  }

  Future<String?> saveGood(GoodResponseEntity good) async {
    ResponseEntity? status;
    if (good.id != null) {
      status = await _api.dictionarySave('/goods_goods_edit', good.toJson());
    } else {
      status = await _api.dictionarySave('/goods_goods_add', good.toJson());
    }
    String? message = getErrorMsg(status);

    return message;
  }

  Future<String?> deleteGood(GoodResponseEntity good) async {
    ResponseEntity status =
        await _api.dictionarySave('/goods_goods_delete', good.toJson());
    String? message = getErrorMsg(status);
    return message;
  }

  Future<List<ContragentResponseEntity>> getContragents(
      {int? page, int? perpage, String? query}) async {
    final List<ContragentResponseEntity> list = [];
    try {
      final Map<String, dynamic> requestBody = <String, dynamic>{
        'page': page,
        'perpage': perpage,
        'filter': [
          {'col': 'name', 'action': 'like', 'val': query ?? ''}
        ]
      };
      final ResponseEntity contragents = await _api
          .postRequest('/general_contragents_get', requestBody: requestBody);
      if (contragents.original.data != null) {
        if (contragents.original.data!.isNotEmpty) {
          for (dynamic map in contragents.original.data!) {
            list.add(ContragentResponseEntity.fromJson(map));
          }
        }
      }
    } catch (e, stack) {
      log.e('getContragents', e, stack);
    }
    return list;
  }

  Future<String?> saveContragent(ContragentResponseEntity contragent) async {
    ResponseEntity? status;
    if (contragent.id != null) {
      status = await _api.dictionarySave(
          '/general_contragents_edit', contragent.toJson());
    } else {
      status = await _api.dictionarySave(
          '/general_contragents_add', contragent.toJson());
    }
    String? message = getErrorMsg(status);

    return message;
  }

  Future<String?> deleteContragent(ContragentResponseEntity contragent) async {
    ResponseEntity status = await _api.dictionarySave(
        '/general_contragents_delete', contragent.toJson());
    String? message = getErrorMsg(status);
    return message;
  }

  String? getErrorMsg(ResponseEntity status) {
    String? message;

    if (status.exception != null) {
      message = status.exception;
    } else if (status.original.message != null) {
      message = status.original.message;
    } else if (status.original.errors != null) {
      Map<String, List<String>> errors = status.original.errors!;
      errors.values.forEach((element) {
        message = '${message ?? ''} \n ${element.join(',')}';
      });
    }
    return message;
  }
}
