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");
const Sequelize = require("sequelize");
const {
  createAuditTrail,
  getSellerAuditTrailPaginate,
} = require("../../helpers/sellerAuditTrail.service");
const { Op } = require("sequelize");

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(async (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",
      });

      const trail = await createAuditTrail({
        seller_id: sellerDetails.id,
        seller_company_id: sellerDetails.seller_id,
        module: "Accounts",
        action: "login",
      });

      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, seller_account_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,
          id: { [Op.ne]: seller_id },
        },
        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,
        },
      }
    );

    const trail = await createAuditTrail({
      seller_id: seller_account_id,
      seller_company_id: seller_id,
      module: "Accounts",
      action: "update - Basic Details",
      action_description: JSON.stringify(updateJson),
    });

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

exports.updateSellerOrBannerImage = async (req, res, next) => {
  try {
    const { seller_id, seller_account_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,
      },
    });

    const trail = await createAuditTrail({
      seller_id: seller_account_id,
      seller_company_id: seller_id,
      module: "Accounts",
      action: "update - Image",
      action_description: JSON.stringify(filteredUpdateJson),
    });

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

exports.updateSellerShippingSettings = async (req, res, next) => {
  try {
    const { seller_id, seller_account_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,
      display_price_in_releasing,
    } = 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,
      display_price_in_releasing: display_price_in_releasing,
    };

    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,
      },
    });

    const trail = await createAuditTrail({
      seller_id: seller_account_id,
      seller_company_id: seller_id,
      module: "Accounts",
      action: "update - Shipping Fees",
      action_description: JSON.stringify(filteredUpdateJson),
    });

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

exports.sellerChangePassword = async (req, res, next) => {
  const { seller_id, seller_account_id } = req;
  try {
    const { new_password, old_password } = req.body;
    if (!new_password || !old_password)
      return res.status(400).json({
        success: false,
        message: "New Password or Old Password empty.",
      });

    const sellerAccount = await Seller.findByPk(seller_account_id);

    if (!sellerAccount)
      return res
        .status(400)
        .json({ success: false, message: "Seller not found." });

    const currentPassword = sellerAccount.password;

    if (currentPassword !== old_password) {
      return res
        .status(400)
        .json({ success: false, message: "Old password not matched." });
    }

    sellerAccount.password = new_password;

    await sellerAccount.save();

    const trail = await createAuditTrail({
      seller_id: seller_account_id,
      seller_company_id: seller_id,
      module: "Accounts",
      action: "update - Password",
      action_description: "",
    });

    res.status(200).json({
      success: true,
      message: "Password successfully changed",
    });
  } catch (err) {
    next(err);
  }
};

exports.sellerForgotPassword = async (req, res, next) => {
  const { seller_id, seller_account_id } = req;
  try {
  } catch (err) {
    next(err);
  }
};

exports.getAllSellerAccounts = async (req, res, next) => {
  try {
    const { seller_id, seller_account_id } = req;
    const { limit = 10, page = 1 } = req.pagination || {};
    const { query = "" } = req.query;

    const offset = (page - 1) * limit;

    const whereClause = {
      seller_id,
    };

    if (query.trim() !== "") {
      whereClause[Sequelize.Op.or] = [
        { name: { [Sequelize.Op.like]: `%${query}%` } },
        { username: { [Sequelize.Op.like]: `%${query}%` } },
      ];
    }

    const { rows: sellerAccounts, count: total } = await Seller.findAndCountAll(
      {
        where: whereClause,
        attributes: [
          "id",
          "seller_id",
          "name",
          "username",
          "isAuthorizedWarehouse",
        ],
        limit,
        offset,
        order: [["name", "ASC"]],
      }
    );

    const trail = await createAuditTrail({
      seller_id: seller_account_id,
      seller_company_id: seller_id,
      module: "Accounts",
      action: "view - Accounts",
      action_description: "",
    });

    res.status(200).json({
      success: true,
      seller_accounts: sellerAccounts,
      total,
      page: Number(page),
      totalPages: Math.ceil(total / limit),
    });
  } catch (err) {
    next(err);
  }
};

exports.editSellerAccount = async (req, res, next) => {
  try {
    const { seller_account_id, seller_id } = req;
    const { account_id } = req.params;
    const { name, username, password, isAuthorizedWarehouse = "No" } = req.body;

    const updateJson = {
      name,
      username,
      password,
      isAuthorizedWarehouse,
    };

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

    const sellerAccount = await Seller.findOne({
      where: {
        seller_id,
        id: account_id,
      },
    });

    if (!sellerAccount) {
      return res.status(200).json({
        success: false,
        message: "Seller account not found.",
      });
    }

    if (username) {
      const existingAccount = await Seller.findOne({
        where: {
          username,
          id: { [Sequelize.Op.ne]: account_id },
        },
      });

      if (existingAccount) {
        return res.status(200).json({
          success: false,
          message: "The username is already taken by another account.",
        });
      }
    }

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

    const trail = await createAuditTrail({
      seller_id: seller_account_id,
      seller_company_id: seller_id,
      module: "Accounts",
      action: "edit - Accounts",
      action_description: `ID: ${account_id} ${JSON.stringify(
        filteredUpdateJson
      )}`,
    });

    res.status(200).json({
      success: true,
      msg: "Account updated.",
      updatedProperties: filteredUpdateJson,
    });
  } catch (err) {
    next(err);
  }
};

exports.deleteSellerAccount = async (req, res, next) => {
  try {
    const { seller_account_id, seller_id } = req;
    const { account_id } = req.params;

    const sellerAccount = await Seller.findOne({
      where: {
        seller_id: seller_id,
        id: account_id,
      },
    });

    if (!sellerAccount)
      return res
        .status(401)
        .json({ success: false, message: "Invalid seller" });

    await Seller.destroy({
      where: {
        seller_id: seller_id,
        id: account_id,
      },
    });

    const trail = await createAuditTrail({
      seller_id: seller_account_id,
      seller_company_id: seller_id,
      module: "Accounts",
      action: "delete - Accounts",
      action_description: `ID: ${account_id}`,
    });

    res.status(200).json({
      success: true,
      message: "Account deleted.",
    });
  } catch (err) {
    next(err);
  }
};
exports.createSellerAccount = async (req, res, next) => {
  try {
    const { seller_account_id, seller_id } = req;
    const { name, username, password, isAuthorizedWarehouse = "No" } = req.body;

    if (!name || !username || !password) {
      return res.status(200).json({
        success: false,
        message: "Name, username, and password are required.",
      });
    }

    if (typeof password !== "string" || password.length < 3) {
      return res.status(200).json({
        success: false,
        message: "Password must be at least 3 characters long.",
      });
    }

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

    if (existingAccount) {
      return res.status(200).json({
        success: false,
        message: "The username is already taken.",
      });
    }

    const createdAccount = await Seller.create({
      name,
      username,
      password,
      seller_id,
      isAuthorizedWarehouse: isAuthorizedWarehouse,
    });

    const trail = await createAuditTrail({
      seller_id: seller_account_id,
      seller_company_id: seller_id,
      module: "Accounts",
      action: "create - Accounts",
      action_description: `ID: ${createdAccount.id}`,
    });

    res.status(201).json({
      success: true,
      message: "Account created.",
    });
  } catch (err) {
    next(err);
  }
};

exports.getAuditTrail = async (req, res, next) => {
  try {
    const { seller_id } = req;
    const { page, limit, keyword } = req.body;

    const response = await getSellerAuditTrailPaginate({
      page,
      limit,
      keyword,
      seller_id,
    });

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