import 'dart:async';

import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/request/conform_allocation/conform_allocation.dart';
import 'package:rasadyar_chicken/data/models/request/submit_steward_allocation/submit_steward_allocation.dart';
import 'package:rasadyar_chicken/data/models/response/allocated_made/allocated_made.dart';
import 'package:rasadyar_chicken/data/models/response/broadcast_price/broadcast_price.dart';
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
import 'package:rasadyar_chicken/data/models/response/guild_profile/guild_profile.dart';
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
import 'package:rasadyar_chicken/presentation/pages/steward/root/logic.dart';
import 'package:rasadyar_chicken/presentation/pages/steward/sale/logic.dart';
import 'package:rasadyar_chicken/presentation/utils/string_utils.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';

class SalesInProvinceLogic extends GetxController {
  StewardRootLogic rootLogic = Get.find<StewardRootLogic>();
  SaleLogic saleLogic = Get.find<SaleLogic>();
  RxnString searchedValue = RxnString();
  RxInt expandedListIndex = (-1).obs;
  RxList<String> routesName = RxList();
  Rx<Color> bgConfirmAllColor = AppColor.blueNormal.obs;
  final RxBool isLoadingMoreAllocationsMade = false.obs;
  Timer? _flashingTimer;

  Rx<Resource<PaginationModel<AllocatedMadeModel>>> allocatedList =
      Resource<PaginationModel<AllocatedMadeModel>>.loading().obs;

  RxList<ProductModel> rolesProductsModel = RxList<ProductModel>();

  RxList<GuildModel> guildsModel = <GuildModel>[].obs;

  GlobalKey<FormState> formKey = GlobalKey<FormState>();

  Rx<Jalali> fromDateFilter = Jalali.now().obs;
  Rx<Jalali> toDateFilter = Jalali.now().obs;
  Rxn<ProductModel> selectedProductModel = Rxn<ProductModel>();
  Rxn<GuildModel> selectedGuildModel = Rxn<GuildModel>();
  Rxn<GuildProfile> guildProfile = Rxn<GuildProfile>();
  RxInt saleType = 1.obs;
  RxInt priceType = 1.obs;
  RxInt quotaType = 1.obs;
  RxInt weight = 0.obs;
  RxInt pricePerKilo = 0.obs;
  RxInt totalCost = 0.obs;
  RxBool isValid = false.obs;
  final weightController = TextEditingController();
  final pricePerKiloController = TextEditingController();
  final totalCostController = TextEditingController();

  final ScrollController scrollControllerAllocationsMade = ScrollController();
  final RxInt currentPage = 1.obs;
  final RxBool addPageAllocationsMade = false.obs;
  final RxBool hasMoreDataAllocationsMade = true.obs;

  Rxn<BroadcastPrice> broadcastPrice = Rxn<BroadcastPrice>();
  Rxn<AllocatedMadeModel> selectedAllocationModelForUpdate = Rxn<AllocatedMadeModel>();
  SubmitStewardAllocation? tmpStewardAllocation;

  @override
  void onInit() {
    super.onInit();
    routesName.value = [...saleLogic.routesName, 'داخل استان'].toList();
    getAllocatedMade();
    getRolesProducts();
    getGuilds();
    getGuildProfile();
    getBroadcastPrice();
    ever(saleType, (callback) {
      getGuilds();
    });

    debounce(weight, time: Duration(milliseconds: 110), (callback) {
      totalCost.value = callback * pricePerKilo.value;
    });

    debounce(pricePerKilo, time: Duration(milliseconds: 100), (callback) {
      totalCost.value = callback * weight.value;
    });

    totalCost.listen((data) {
      totalCostController.text = data.toString().separatedByComma;

      isValid.value =
          weight.value > 0 &&
          pricePerKilo.value > 0 &&
          totalCost.value > 0 &&
          selectedProductModel.value != null &&
          selectedGuildModel.value != null;
    });
    everAll([
      totalCost,
      weight,
      pricePerKilo,
      totalCost,
      selectedProductModel,
      selectedGuildModel,
    ], (callback) => checkVerification());

    scrollControllerAllocationsMade.addListener(() {
      if (scrollControllerAllocationsMade.position.pixels >=
          scrollControllerAllocationsMade.position.maxScrollExtent - 100) {
        addPageAllocationsMade.value = true;
        getAllocatedMade();
      }
    });

    debounce(
      searchedValue,
      (callback) => getAllocatedMade(),
      time: Duration(milliseconds: timeDebounce),
    );
  }

  Future<void> getAllocatedMade([bool isLoadingMore = false]) async {
    if (isLoadingMore) {
      isLoadingMoreAllocationsMade.value = true;
    } else {
      allocatedList.value = Resource<PaginationModel<AllocatedMadeModel>>.loading();
    }

    if (searchedValue.value != null &&
        searchedValue.value!.trim().isNotEmpty &&
        currentPage.value > 1) {
      currentPage.value = 1; // Reset to first page if search value is set
    }

    safeCall(
      call: () async => await rootLogic.chickenRepository.getAllocatedMade(
        token: rootLogic.tokenService.accessToken.value!,
        queryParameters: buildQueryParams(
          page: currentPage.value,
          pageSize: 20,
          search: 'filter',
          role: 'Steward',
          value: searchedValue.value,
          fromDate: fromDateFilter.value.toDateTime(),
          toDate: toDateFilter.value.toDateTime(),
        ),
      ),
      onSuccess: (res) async {
        await Future.delayed(Duration(milliseconds: 200));
        if ((res?.count ?? 0) == 0) {
          allocatedList.value = Resource<PaginationModel<AllocatedMadeModel>>.empty();
        } else {
          allocatedList.value = Resource<PaginationModel<AllocatedMadeModel>>.success(
            PaginationModel<AllocatedMadeModel>(
              count: res?.count ?? 0,
              next: res?.next,
              previous: res?.previous,
              results: isLoadingMore
                  ? [...(allocatedList.value.data?.results ?? []), ...(res?.results ?? [])]
                  : res?.results ?? [],
            ),
          );
          isLoadingMoreAllocationsMade.value = false;
          if ((allocatedList.value.data?.results?.length ?? 0) > 1) {
            flashingFabBgColor();
          }
        }
      },
      onError: (error, stacktrace) {
        isLoadingMoreAllocationsMade.value = false;
      },
    );
  }

  void checkVerification() {
    isValid.value =
        weight.value > 0 &&
        pricePerKilo.value > 0 &&
        totalCost.value > 0 &&
        selectedProductModel.value != null &&
        selectedGuildModel.value != null;
  }

  void confirmAllocation(ConformAllocation allocation) {
    safeCall(
      call: () async => await rootLogic.chickenRepository.confirmAllocation(
        token: rootLogic.tokenService.accessToken.value!,
        allocation: allocation.toJson(),
      ),
      onSuccess: (result) {
        getAllocatedMade();
      },
      onError: (error, stacktrace) {},
    );
  }

  void denyAllocation(String token) {
    safeCall(
      call: () async => await rootLogic.chickenRepository.denyAllocation(
        token: rootLogic.tokenService.accessToken.value!,
        allocationToken: token,
      ),
      onSuccess: (result) {
        getAllocatedMade();
      },
      onError: (error, stacktrace) {},
    );
  }

  Future<void> confirmAllAllocations() async {
    safeCall(
      call: () async => await rootLogic.chickenRepository.confirmAllAllocation(
        token: rootLogic.tokenService.accessToken.value!,
        allocationTokens: allocatedList.value.data?.results?.map((e) => e.key!).toList() ?? [],
      ),
      onSuccess: (result) {
        getAllocatedMade();
      },
      onError: (error, stacktrace) {},
    );
  }

  Future<void> getRolesProducts() async {
    safeCall(
      call: () async => await rootLogic.chickenRepository.getRolesProducts(
        token: rootLogic.tokenService.accessToken.value!,
      ),
      onSuccess: (result) {
        if (result != null) {
          rolesProductsModel.value = result;
          selectedProductModel.value = result.first;
        }
      },
      onError: (error, stacktrace) {},
    );
  }

  Future<void> getGuilds() async {
    safeCall(
      call: () async => await rootLogic.chickenRepository.getGuilds(
        token: rootLogic.tokenService.accessToken.value!,
        queryParameters: buildQueryParams(
          queryParams: {'free': saleType.value == 2 ? true : false},
          role: 'Steward',
        ),
      ),
      onSuccess: (result) {
        if (result != null) {
          guildsModel.clear();
          guildsModel.addAll(result);
        }
      },
      onError: (error, stacktrace) {},
    );
  }

  Future<void> addSale() async {}

  void setSelectedGuild(GuildModel value) {
    selectedGuildModel.value = value;
    update();
  }

  void setSelectedProduct(ProductModel value) {
    selectedProductModel.value = value;
    update();
  }

  Future<void> getGuildProfile() async {
    await safeCall(
      call: () async => await rootLogic.chickenRepository.getProfile(
        token: rootLogic.tokenService.accessToken.value!,
      ),
      onError: (error, stackTrace) {},
      onSuccess: (result) {
        guildProfile.value = result;
      },
    );
  }

  void setSubmitData() {
    tmpStewardAllocation = SubmitStewardAllocation(
      approvedPriceStatus: broadcastPrice.value?.active ?? false,
      allocationType:
          '${guildProfile.value?.steward == true ? "steward" : "guild"}_${selectedGuildModel.value?.steward == true ? "steward" : "guild"}',
      sellerType: guildProfile.value?.steward == true ? "Steward" : "Guild",
      buyerType: selectedGuildModel.value?.steward == true ? "Steward" : "Guild",
      amount: pricePerKilo.value,
      totalAmount: totalCost.value,
      weightOfCarcasses: weight.value,
      sellType: saleType.value == 2 ? "free" : 'exclusive',
      numberOfCarcasses: 0,
      quota: quotaType.value == 1 ? 'governmental' : 'free',
      guildKey: selectedGuildModel.value?.key,
      productKey: selectedProductModel.value?.key,
      date: DateTime.now().formattedDashedGregorian,
      type: "manual",
    );
  }

  Future<void> submitAllocation() async {
    setSubmitData();

    safeCall(
      showError: true,
      call: () async => await rootLogic.chickenRepository.postSubmitStewardAllocation(
        token: rootLogic.tokenService.accessToken.value!,
        request: tmpStewardAllocation!,
      ),

      onSuccess: (result) {
        clearForm();
        onRefresh();
        rootLogic.onRefresh();
      },
      onError: (error, stackTrace) {},
    );
  }

  Future<void> deleteAllocation(AllocatedMadeModel model) async {
    safeCall(
      call: () async => await rootLogic.chickenRepository.deleteStewardAllocation(
        token: rootLogic.tokenService.accessToken.value!,
        queryParameters: {'steward_allocation_key': model.key},
      ),

      onSuccess: (result) {
        getAllocatedMade();
      },
      onError: (error, stackTrace) {},
    );
  }

  @override
  void dispose() {
    rootLogic.inventoryExpandedList.clear();
    stopFlashing();
    super.dispose();
  }

  void setEditData(AllocatedMadeModel item) {
    selectedAllocationModelForUpdate.value = item;
    selectedProductModel.value = rolesProductsModel.first;
    selectedGuildModel.value = GuildModel(guildsName: 'tst');
    weight.value = item.weightOfCarcasses ?? 0;
    pricePerKilo.value = item.amount ?? 0;
    totalCost.value = item.totalAmount ?? 0;
    weightController.text = weight.value.toString().separatedByComma;
    pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
    totalCostController.text = totalCost.value.toString().separatedByComma;
    isValid.value = true;
  }

  void clearForm() {
    selectedGuildModel.value = null;
    weight.value = 0;

    totalCost.value = 0;
    weightController.clear();
    if (broadcastPrice.value?.active == false) {
      pricePerKilo.value = 0;
      pricePerKiloController.clear();
    }

    totalCostController.clear();
    isValid.value = false;
  }

  Future<void> updateAllocation() async {
    ConformAllocation updatedAllocationModel = ConformAllocation(
      allocation_key: selectedAllocationModelForUpdate.value?.key,
      amount: pricePerKilo.value,
      total_amount: totalCost.value,
      number_of_carcasses: 0,
      weight_of_carcasses: weight.value,
    );

    safeCall(
      showError: true,
      call: () async => await rootLogic.chickenRepository.updateStewardAllocation(
        token: rootLogic.tokenService.accessToken.value!,
        request: updatedAllocationModel,
      ),

      onSuccess: (result) {
        clearForm();
        onRefresh();
        rootLogic.onRefresh();
      },
      onError: (error, stackTrace) {},
    );
  }

  void setSearchValue(String? data) {
    searchedValue.value = data?.trim();
  }

  void flashingFabBgColor() {
    _flashingTimer?.cancel();

    _flashingTimer = Timer.periodic(Duration(seconds: 2), (timer) {
      if (bgConfirmAllColor.value == AppColor.blueNormal) {
        bgConfirmAllColor.value = AppColor.blueLightHover;
      } else {
        bgConfirmAllColor.value = AppColor.blueNormal;
      }
    });
  }

  void stopFlashing() {
    _flashingTimer?.cancel();
    _flashingTimer = null;
    bgConfirmAllColor.value = AppColor.blueNormal; // بازگرداندن به رنگ پیش‌فرض
  }

  Steward? getBuyerInformation(AllocatedMadeModel model) {
    if (model.allocationType?.buyerIsGuild) {
      return model.toGuilds;
    } else {
      return model.steward;
    }
  }

  Future<void> getBroadcastPrice() async {
    safeCall(
      call: () async => await rootLogic.chickenRepository.getBroadcastPrice(
        token: rootLogic.tokenService.accessToken.value!,
      ),
      onSuccess: (result) {
        broadcastPrice.value = result;
        if (broadcastPrice.value?.active == true) {
          pricePerKilo.value = broadcastPrice.value?.stewardPrice ?? 0;
          pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
        }
      },
      onError: (error, stacktrace) {},
    );
  }

  Future<void> onRefresh() async {
    toggleExpansion();
    currentPage.value = 1;
    hasMoreDataAllocationsMade.value = true;
    await Future.wait([getAllocatedMade(), rootLogic.onRefresh()]);
  }

  void toggleExpansion({int? index}) {
    if (expandedListIndex.value == index || index == null) {
      expandedListIndex.value = -1;
    } else {
      expandedListIndex.value = index;
    }
  }
}
