const Customers = require("../../models/Customers");
const UserCart = require("../../models/UserCart");
const Products = require("../../models/Products");
const SellersCompany = require("../../models/SellersCompany");
const ProductMenu = require("../../models/ProductMenu");
const Fees = require("../../models/Fees");
const computeDistance = require("../../helpers/computeDistance");
const checkSellerShipping = require("../../helpers/sellerShippingComputeDistance");

const logger = require("../../util/logger");
const { lalamoveShipping } = require("../../helpers/shipping.service");
const SellersCompanyWarehouses = require("../../models/SellersCompanyWarehouses");

exports.getShippingFee = async (req, res, next) => {
  const { customerId } = req;
  const {
    customLongitude = "0",
    customLatitude = "0",
    customAddress = "",
    orderSubTotal = "0",
  } = req.query;

  let customerLat,
    customerLng,
    sellerCompanyId,
    sellerLat,
    sellerLng,
    productMenuCategory,
    compututationMethod,
    smallItemPerKm,
    smallItemFixed,
    bigItemPerKm,
    bigItemFixed,
    flagdownBig,
    flagdownSmall,
    inHouseSmallPerKm,
    inHouseSmallFixed,
    inHouseBigPerKm,
    inHouseBigFixed,
    inHouseFlagdownBig,
    inHouseFlagdownSmall,
    defaultShippingFee,
    sellerShippingSettings,
    enabledSellerShipping = false,
    customerAddress = "",
    sellerAddress = "";

  const defaultShipping = await Fees.findOne({
    where: {
      fee: "Shipping",
    },
  });

  defaultShippingFee = parseFloat(defaultShipping.amount);

  Customers.findByPk(customerId)
    .then((customerDetail) => {
      const { latitude, longitude, address } = customerDetail;
      if (!latitude || !longitude) {
        return res
          .status(200)
          .json({ success: false, msg: "Customer location not set!" });
      }
      customerLat = latitude;
      customerLng = longitude;
      customerAddress = address;

      // QUICK FIX
      if (
        customLongitude !== "0" &&
        customLatitude !== "0" &&
        customLongitude !== "" &&
        customLatitude !== ""
      ) {
        customerLat = customLatitude;
        customerLng = customLongitude;
        customerAddress = customAddress;
      }

      return UserCart.findAll({
        where: {
          user_id: customerId,
        },
        attributes: [
          "menu_id",
          "quantity",
          "price",
          "has_sub_variation_chosen",
          "product_variation_id",
          "product_sub_variation_id",
        ],
        include: [
          {
            model: Products,
            as: "product",
            include: [
              {
                model: SellersCompany,
                as: "seller",
                include: [
                  {
                    model: SellersCompanyWarehouses,
                    as: "seller_warehouse",
                  },
                ],
              },
              {
                model: ProductMenu,
                as: "menus",
              },
            ],
          },
        ],
      });
    })
    .then(async (userCartDetail) => {
      if (userCartDetail.length === 0) {
        return res
          .status(200)
          .json({ success: false, msg: "User has empty cart!" });
      }

      productMenuCategory = userCartDetail[0].product.menus.size_category;

      sellerCompanyId = userCartDetail[0].product.seller.id;
      sellerLat = userCartDetail[0].product.seller.latitude;
      sellerLng = userCartDetail[0].product.seller.longitude;
      sellerAddress = userCartDetail[0].product.seller.address;
      compututationMethod = userCartDetail[0].product.seller.computation_method;
      smallItemFixed = userCartDetail[0].product.seller.small_item_fee_fixed;
      smallItemPerKm = userCartDetail[0].product.seller.small_item_fee_perkm;
      bigItemFixed = userCartDetail[0].product.seller.big_item_fee_fixed;
      bigItemPerKm = userCartDetail[0].product.seller.big_item_fee_perkm;
      flagdownBig = userCartDetail[0].product.seller.flagdownBigKM;
      flagdownSmall = userCartDetail[0].product.seller.flagdownSmallKM;
      inHouseBigFixed = userCartDetail[0].product.seller.in_house_big_fixed;
      inHouseBigPerKm = userCartDetail[0].product.seller.in_house_big_per_km;
      inHouseSmallFixed = userCartDetail[0].product.seller.in_house_small_fixed;
      inHouseSmallPerKm =
        userCartDetail[0].product.seller.in_house_small_per_km;
      inHouseFlagdownBig =
        userCartDetail[0].product.seller.in_house_flagdown_big_km;
      inHouseFlagdownSmall =
        userCartDetail[0].product.seller.in_house_flagdown_small_km;

      enabledSellerShipping =
        userCartDetail[0].product.seller.enabled_seller_shipping;
      sellerType = userCartDetail[0].product.seller.seller_type;
      sellerShippingRadius =
        userCartDetail[0].product.seller.seller_radius_shipping;

      const userCartSellerDetails = userCartDetail[0].product.seller;
      if (
        userCartSellerDetails &&
        userCartSellerDetails.warehouse_id &&
        userCartSellerDetails.seller_warehouse
      ) {
        sellerLat = userCartSellerDetails.seller_warehouse.latitude;
        sellerLng = userCartSellerDetails.seller_warehouse.longitude;
        compututationMethod =
          userCartSellerDetails.seller_warehouse.computation_method;

        // Get the Fees from Warehouse since it has warehouse defined.
        smallItemPerKm =
          userCartSellerDetails.seller_warehouse.small_item_perkm;
        smallItemFixed =
          userCartSellerDetails.seller_warehouse.small_item_fixed;
        bigItemPerKm = userCartSellerDetails.seller_warehouse.big_item_perkm;
        bigItemFixed = userCartSellerDetails.seller_warehouse.big_item_fixed;

        flagdownSmall =
          userCartSellerDetails.seller_warehouse.small_item_flagdown_perkm;
        flagdownBig =
          userCartSellerDetails.seller_warehouse.big_item_flagdown_perkm;
      }
      if (!sellerLat || !sellerLng) {
        return res
          .status(200)
          .json({ success: false, msg: "Seller location not set!" });
      }

      sellerShippingSettings = await checkSellerShipping(
        customerLat,
        customerLng,
        sellerLat,
        sellerLng,
        sellerShippingRadius
      );

      if (sellerShippingSettings) {
        enabledSellerShipping =
          sellerShippingSettings.seller_shipping_within_range &&
          enabledSellerShipping &&
          sellerType !== "Internal";

        logger.error(`ENABLED SELLER SHIPPING: ${enabledSellerShipping}`);
        logger.error(
          `SELLER SHIPPING WITHIN RANGE: ${sellerShippingSettings.seller_shipping_within_range}`
        );
        logger.error(`SELLER TYPE: ${sellerType}`);
      }
      return computeDistance(
        `${customerLat},${customerLng}`,
        `${sellerLat},${sellerLng}`
      );
    })
    .then(async (customerDistanceKm) => {
      let standardShippingFee, standardShippingRate, standardShippingFlagdown;
      let hardwareShippingFee, hardwareShippingRate, hardwareShippingFlagdown;

      const inHousePerKmValues = [
        inHouseBigPerKm,
        inHouseSmallPerKm,
        inHouseFlagdownBig,
        inHouseFlagdownSmall,
      ];

      const inHouseFixedValues = [inHouseBigFixed, inHouseSmallFixed];

      switch (compututationMethod.toLowerCase()) {
        case "perkm":
          const hasInvalidInHousePerKmValue = inHousePerKmValues.some(
            (val) =>
              val === null || val === undefined || val === "" || isNaN(val)
          );

          if (hasInvalidInHousePerKmValue) {
            enabledSellerShipping = false;
          }
          if (productMenuCategory.toLowerCase() === "small item") {
            // Standard Shipping
            standardShippingFee =
              parseFloat(smallItemPerKm) * customerDistanceKm +
              parseFloat(flagdownSmall);
            standardShippingRate = parseFloat(smallItemPerKm);
            standardShippingFlagdown = parseFloat(flagdownSmall);

            // Hardware Shipping
            hardwareShippingFee =
              parseFloat(inHouseSmallPerKm) * customerDistanceKm +
              parseFloat(inHouseFlagdownSmall);
            hardwareShippingRate = parseFloat(inHouseSmallPerKm);
            hardwareShippingFlagdown = parseFloat(inHouseFlagdownSmall);
          } else if (productMenuCategory.toLowerCase() === "large item") {
            // Standard Shipping
            standardShippingFee =
              parseFloat(bigItemPerKm) * customerDistanceKm +
              parseFloat(flagdownBig);
            standardShippingRate = parseFloat(bigItemPerKm);
            standardShippingFlagdown = parseFloat(flagdownBig);

            // Hardware Shipping
            hardwareShippingFee =
              parseFloat(inHouseBigPerKm) * customerDistanceKm +
              parseFloat(inHouseFlagdownBig);
            hardwareShippingRate = parseFloat(inHouseBigPerKm);
            hardwareShippingFlagdown = parseFloat(inHouseFlagdownBig);
          }
          break;
        case "fixed":
          const hasInvalidInHouseFixedValue = inHouseFixedValues.some(
            (val) =>
              val === null || val === undefined || val === "" || isNaN(val)
          );

          if (hasInvalidInHouseFixedValue) {
            enabledSellerShipping = false;
          }
          if (productMenuCategory.toLowerCase() === "small item") {
            // Standard Shipping
            standardShippingFee =
              parseFloat(smallItemFixed) + parseFloat(flagdownSmall);
            standardShippingRate = parseFloat(smallItemFixed);
            standardShippingFlagdown = parseFloat(flagdownSmall);

            // Hardware Shipping
            hardwareShippingFee =
              parseFloat(inHouseSmallFixed) + parseFloat(inHouseFlagdownSmall);
            hardwareShippingRate = parseFloat(inHouseSmallFixed);
            hardwareShippingFlagdown = parseFloat(inHouseFlagdownSmall);
          } else if (productMenuCategory.toLowerCase() === "large item") {
            // Standard Shipping
            standardShippingFee =
              parseFloat(bigItemFixed) + parseFloat(flagdownBig);
            standardShippingRate = parseFloat(bigItemFixed);
            standardShippingFlagdown = parseFloat(flagdownBig);

            // Hardware Shipping
            hardwareShippingFee =
              parseFloat(inHouseBigFixed) + parseFloat(inHouseFlagdownBig);
            hardwareShippingRate = parseFloat(inHouseBigFixed);
            hardwareShippingFlagdown = parseFloat(inHouseFlagdownBig);
          }
          break;
        default:
          standardShippingFee = defaultShippingFee;
          standardShippingRate = defaultShippingFee;
          standardShippingFlagdown = 0;
          break;
      }

      const lalamoveShippingQuote = await lalamoveShipping({
        customerLng: customerLng,
        customerLat: customerLat,
        customerAdd: customerAddress,
        sellerLng: sellerLng,
        sellerLat: sellerLat,
        sellerAdd: sellerAddress,
        orderSubTotal: parseFloat(orderSubTotal),
      });

      let lalamoveResponse = null;
      if (lalamoveShippingQuote && lalamoveShippingQuote.data) {
        const customerStopId = lalamoveShippingQuote.data.stops[0].stopId;
        const sellerStopId = lalamoveShippingQuote.data.stops[1].stopId;

        lalamoveResponse = {
          quotation_id: lalamoveShippingQuote.data.quotationId,
          schedule_at: lalamoveShippingQuote.data.scheduleAt,
          expires_at: lalamoveShippingQuote.data.expiresAt,
          service_type: lalamoveShippingQuote.data.serviceType,
          fee: lalamoveShippingQuote.data.priceBreakdown.total,
          distance: {
            value: lalamoveShippingQuote.data.distance.value,
            unit: lalamoveShippingQuote.data.distance.unit,
          },
          customer_stop_id: customerStopId,
          seller_stop_id: sellerStopId,
        };
      }

      res.status(200).json({
        success: true,
        standard_shipping: {
          fee: Math.round(standardShippingFee),
          total_distance_to_seller: customerDistanceKm,
          compututationMethod,
          product_category: productMenuCategory,
          rate: standardShippingRate,
          flagdown: standardShippingFlagdown,
          seller: sellerCompanyId,
        },
        hardware_shipping: {
          fee: enabledSellerShipping ? Math.round(hardwareShippingFee) : 0,
          total_distance_to_seller: enabledSellerShipping
            ? customerDistanceKm
            : 0,
          compututationMethod,
          product_category: productMenuCategory,
          rate: enabledSellerShipping ? hardwareShippingRate : 0,
          flagdown: enabledSellerShipping ? hardwareShippingFlagdown : 0,
          enabled_hardware_shipping: enabledSellerShipping,
          hardware_shipping_configs: sellerShippingSettings,
        },
        lalamove_shipping: lalamoveResponse,
      });
    })
    .catch((err) => {
      next(err);
    });
};
