const Seller = require("../../models/Seller");
const SellersCompany = require("../../models/SellersCompany");
const jwt = require("jsonwebtoken");
const slugify = require("slugify");

const { sellerImageBuilder, sellerProductImageBuilder } = require("../../helpers/image-src-builder");

exports.SELLERS_SECRET_KEY = "5njDYq#$+!QfsxU67qU!Dkg9Y4j59@";

exports.accountLogin = (req, res, next) => {
  const { username, password } = req.body;

  let sellerDetails;
  Seller.findOne({
    where: {
      username,
      password,
    },
  })
    .then((sellerDetail) => {
      if (!sellerDetail) return res.status(404).json({ success: false, msg: "Account not found." });

      sellerDetails = sellerDetail;
      return SellersCompany.findByPk(sellerDetail.seller_id);
    })
    .then((sellerCompanyDetail) => {
      if (!sellerCompanyDetail) return res.status(404).json({ success: false, msg: "Seller Company not found." });

      const tokenDetails = {
        seller_id: sellerDetails.seller_id,
        seller_account_id: sellerDetails.id,
      };

      const token = jwt.sign(tokenDetails, this.SELLERS_SECRET_KEY, {
        expiresIn: "2h",
      });

      res.status(200).json({
        success: true,
        token,
        isAuthorizedWarehouse: sellerDetails.isAuthorizedWarehouse,
        seller_name: sellerDetails.name,
        seller_type: sellerCompanyDetail.seller_type,
      });
    })
    .catch((err) => {
      next(err);
    });
};

exports.myselfDetails = async (req, res, next) => {
  const { seller_id, seller_account_id } = req;

  try {
    const sellerCompanyPromise = SellersCompany.findOne({
      where: {
        id: seller_id,
      },
      attributes: { exclude: ["contact_number", "seller_banner_image_upload", "seller_type"] },
    });
    const sellerAccountPromise = Seller.findOne({
      where: {
        id: seller_account_id,
      },
      attributes: { exclude: ["password", "role", "seller_logo", "description", "lat", "long", "address"] },
    });

    const [sellerCompany, sellerAccount] = await Promise.all([sellerCompanyPromise, sellerAccountPromise]);

    const sellerLogo = sellerImageBuilder(sellerCompany.seller_logo, sellerCompany.seller_dashboard_src);
    const sellerBanner = sellerImageBuilder(sellerCompany.seller_banner_image, sellerCompany.seller_dashboard_src);
    sellerCompany.seller_logo = sellerLogo;
    sellerCompany.seller_banner_image = sellerBanner;
    res.status(200).json({ success: true, company: sellerCompany, seller_account: sellerAccount });
  } catch (err) {
    next(err);
  }
};

exports.sellerCompanySignup = async (req, res, next) => {
  const {
    company_name,
    company_description,
    address,
    display_shop_name = null,
    display_municipality = null,
    display_province = null,
    latitude,
    longitude,
    owner,
    email_address,
    phone_number_primary,
    phone_number_optional_1 = null,
    phone_Number_optional_2 = null,
    initial_username,
    initial_password,
  } = req.body;

  if (
    !company_name ||
    !company_description ||
    !address ||
    !latitude ||
    !longitude ||
    !owner ||
    !email_address ||
    !phone_number_primary
  )
    return res.status(401).json({ success: false, message: "Missing required fields!" });

  try {
    const existingCompany = await SellersCompany.findOne({
      where: {
        company_name,
      },
    });

    const existingSellerAccount = await Seller.findOne({
      where: {
        username: initial_username,
      },
    });

    if (existingCompany || existingSellerAccount)
      return res
        .status(401)
        .json({ success: false, message: "Either company_name or intial_username already exists!" });

    let baseHandle = slugify(display_shop_name?.trim() || company_name?.trim() || "", {
      lower: true,
      remove: /[*+~.()'"!:@]/g,
    });

    let uniqueHandle = baseHandle;
    let counter = 2;

    while (
      await SellersCompany.findOne({
        where: {
          url_handle: uniqueHandle,
        },
      })
    ) {
      uniqueHandle = `${baseHandle}-${counter}`;
      counter++;
    }

    const sellerCompany = await SellersCompany.create({
      company_name,
      company_description,
      address,
      shop_name: display_shop_name,
      shop_location_municipality: display_municipality,
      shop_location_province: display_province,
      url_handle: uniqueHandle,
      latitude,
      longitude,
      owner,
      seller_logo: "empty-seller-image.jpg",
      emailAddress: email_address,
      contact_number: phone_number_primary,
      isParentCompany: "",
      status: false,
      seller_banner_image: "empty-seller-banner-image.jpg",
      seller_type: "External",
      phone_number_primary,
      phone_number_optional_1,
      phone_Number_optional_2,
      enabled_seller_shipping: false,
      seller_radius_shipping: 0,
      seller_dashboard_src: true,
    });

    const sellerAccount = await Seller.create({
      seller_id: sellerCompany.id,
      name: owner,
      username: initial_username,
      password: initial_password,
      address,
      isAuthorizedWarehouse: "Yes",
    });

    res.status(200).json({ success: true, message: "Seller Company has been created with the initial credentials." });
  } catch (err) {
    next(err);
  }
};

exports.updateSellerCompanyBasicDetails = async (req, res, next) => {
  const { seller_id } = req;

  const {
    company_name,
    company_description,
    address,
    display_shop_name,
    display_municipality,
    display_province,
    latitude,
    longitude,
    owner,
    phone_number_primary,
    phone_number_optional_1,
    phone_Number_optional_2,
  } = req.body;
  try {
    const updateJson = {
      company_name,
      company_description,
      address,
      shop_name: display_shop_name,
      shop_location_municipality: display_municipality,
      shop_location_province: display_province,
      latitude,
      longitude,
      owner,
      phone_number_primary,
      phone_number_optional_1,
      phone_Number_optional_2,
    };

    const filteredUpdateJson = Object.fromEntries(
      Object.entries(updateJson).filter(([_, value]) => value != null && value !== "")
    );

    if (company_name) {
      const existingSellerCompanyName = await SellersCompany.findOne({
        where: {
          company_name,
        },
        attributes: ["company_name"],
      });

      if (existingSellerCompanyName)
        return res.status(400).json({ success: false, message: "Company name already exists." });
    }

    const updatedSellerCompany = await SellersCompany.update(filteredUpdateJson, {
      where: {
        id: seller_id,
      },
    });

    res.status(200).json({ success: true, sellers_company: updateJson });
  } catch (err) {
    next(err);
  }
};

exports.updateSellerOrBannerImage = async (req, res, next) => {
  try {
    const { seller_id } = req;

    const { seller_logo, seller_banner } = req.files;

    const updateJson = {
      seller_logo: seller_logo && seller_logo.length > 0 ? seller_logo[0]?.filename : null,
      seller_logo_url: seller_logo && seller_logo.length > 0 ? sellerImageBuilder(seller_logo[0].filename, true) : "",
      seller_banner_image: seller_banner && seller_banner.length > 0 ? seller_banner[0]?.filename : null,
      seller_banner_url:
        seller_banner && seller_banner.length > 0 ? sellerImageBuilder(seller_banner[0].filename, true) : "",
      seller_dashboard_src: true,
    };

    const filteredUpdateJson = Object.fromEntries(
      Object.entries(updateJson).filter(([_, value]) => value != null && value !== "")
    );

    await SellersCompany.update(filteredUpdateJson, {
      where: {
        id: seller_id,
      },
    });

    res.status(200).json({ success: true, seller: filteredUpdateJson });
  } catch (err) {
    next(err);
  }
};

exports.updateSellerShippingSettings = async (req, res, next) => {
  try {
    const { seller_id } = req;
    const {
      computation_method,
      small_item_perkm,
      small_item_fixed,
      big_item_perkm,
      big_item_fixed,
      flagdown_big_km,
      flagdown_small_km,
      own_small_km,
      own_small_fixed,
      own_big_km,
      own_big_fixed,
      own_flagdown_big_km,
      own_flagdown_small_km,
      radius_shipping,
      enable_radius_shipping,
    } = req.body;

    const updateMapping = {
      computation_method,
      small_item_fee_perkm: small_item_perkm,
      small_item_fee_fixed: small_item_fixed,
      big_item_fee_perkm: big_item_perkm,
      big_item_fee_fixed: big_item_fixed,
      flagdownBigKM: flagdown_big_km,
      flagdownSmallKM: flagdown_small_km,
      in_house_small_per_km: own_small_km,
      in_house_small_fixed: own_small_fixed,
      in_house_big_per_km: own_big_km,
      in_house_big_fixed: own_big_fixed,
      in_house_flagdown_big_km: own_flagdown_big_km,
      in_house_flagdown_small_km: own_flagdown_small_km,
      enabled_seller_shipping: enable_radius_shipping,
      seller_radius_shipping: radius_shipping,
    };

    const availableComputations = ["PerKM", "Fixed"];

    if (!availableComputations.includes(computation_method))
      return res.status(400).json({ success: false, message: "Unsupported computation method." });

    const filteredUpdateJson = Object.fromEntries(
      Object.entries(updateMapping).filter(([_, value]) => value != null && value !== "" && value !== 0)
    );

    await SellersCompany.update(filteredUpdateJson, {
      where: {
        id: seller_id,
      },
    });

    res.status(200).json({ success: true, shipping: filteredUpdateJson });
  } catch (err) {
    next(err);
  }
};
