const Products = require("../models/Products");
const Seller = require("../models/Seller");
const SellersCompany = require("../models/SellersCompany");
const DetailProductReviews = require("../models/DetailProductReviews");
const errorHandler = require("../util/errorHandler");

exports.createSellersCompany = (req, res, next) => {
  const { data } = req.body;
  const { parentCompany, childCompany } = data;

  const {
    companyName,
    shopName = "",
    shopLocationMunicipality = "",
    shopLocationProvince = "",
    description,
    address,
    latitude,
    longitude,
    owner,
    computationMethod,
    emailAddress,
    contact_number,
    isParentCompany,
    smallItemFeePerKM,
    smallItemFeeFixed,
    bigItemFeePerKM,
    bigItemFeeFixed,
    flagdownBigKM,
    flagdownSmallKM,
  } = parentCompany;

  const {
    childCompany_companyName,
    childCompany_shopName = "",
    childCompany_shopLocationMunicipality = "",
    childCompany_shopLocationProvince = "",
    childCompany_description,
    childCompany_address,
    childCompany_latitude,
    childCompany_longitude,
    childCompany_owner,
    childCompany_computationMethod,
    childCompany_emailAddress,
    childCompany_contact_number,
    childCompany_smallItemFeePerKM,
    childCompany_smallItemFeeFixed,
    childCompany_bigItemFeePerKM,
    childCompany_bigItemFeeFixed,
    childCompany_flagdownBigKM,
    childCompany_flagdownSmallKM,
  } = childCompany;

  if (!req.files || !req.files.sellerLogo || !req.files.childCompany_sellerLogo) {
    return errorHandler("Seller Logo is missing from the request.", 500);
  }

  const { sellerLogo, childCompany_sellerLogo } = req.files;

  SellersCompany.create({
    shop_name: shopName,
    shop_location_municipality: shopLocationMunicipality,
    shop_location_province: shopLocationProvince,
    company_name: companyName,
    company_description: description,
    address: address,
    latitude: latitude,
    longitude: longitude,
    owner: owner,
    seller_logo: sellerLogo[0].filename || null,
    computation_method: computationMethod,
    emailAddress: emailAddress,
    contact_number: contact_number,
    isParentCompany: isParentCompany,
    small_item_fee_perkm: smallItemFeePerKM,
    small_item_fee_fixed: smallItemFeeFixed,
    big_item_fee_perkm: bigItemFeePerKM,
    big_item_fee_fixed: bigItemFeeFixed,
    flagdownBigKM: flagdownBigKM,
    flagdownSmallKM: flagdownSmallKM,
  })
    .then((parentCompany) => {
      return SellersCompany.create({
        shop_name: childCompany_shopName,
        company_name: childCompany_companyName,
        company_description: childCompany_description,
        address: childCompany_address,
        shop_location_municipality: childCompany_shopLocationMunicipality,
        shop_location_province: childCompany_shopLocationProvince,
        latitude: childCompany_latitude,
        longitude: childCompany_longitude,
        owner: childCompany_owner,
        seller_logo: childCompany_sellerLogo[0].filename || null,
        computation_method: childCompany_computationMethod,
        emailAddress: childCompany_emailAddress,
        contact_number: childCompany_contact_number,
        parent_company: parentCompany.id,
        small_item_fee_perkm: childCompany_smallItemFeePerKM,
        small_item_fee_fixed: childCompany_smallItemFeeFixed,
        big_item_fee_perkm: childCompany_bigItemFeePerKM,
        big_item_fee_fixed: childCompany_bigItemFeeFixed,
        flagdownBigKM: childCompany_flagdownBigKM,
        flagdownSmallKM: childCompany_flagdownSmallKM,
      });
    })
    .then(() => {
      res.status(201).json({ success: true });
    })
    .catch((err) => {
      next(err);
    });
};

exports.createSellersChildCompany = (req, res, next) => {
  const { parentCompanyId } = req.params;
  const { data } = req.body;
  const {
    shopName = "",
    shopLocationMunicipality = "",
    shopLocationProvince = "",
    companyName,
    description,
    address,
    latitude,
    longitude,
    owner,
    computationMethod,
    emailAddress,
    contact_number,
    smallItemFeePerKM,
    smallItemFeeFixed,
    bigItemFeePerKM,
    bigItemFeeFixed,
    flagdownBigKM,
    flagdownSmallKM,
  } = data;

  if (!req.files || !req.files.sellerLogo) {
    return errorHandler("Seller Logo is missing from the request.", 500);
  }

  const { sellerLogo } = req.files;

  SellersCompany.findByPk(parentCompanyId)
    .then((parentCompany) => {
      if (!parentCompany) {
        return errorHandler("Parent Company ID does not exists!", 404);
      }

      return SellersCompany.create({
        shop_name: shopName,
        shop_location_municipality: shopLocationMunicipality,
        shop_location_province: shopLocationProvince,
        company_name: companyName,
        company_description: description,
        address: address,
        latitude: latitude,
        longitude: longitude,
        owner: owner,
        seller_logo: sellerLogo[0].filename || null,
        computation_method: computationMethod,
        emailAddress: emailAddress,
        contact_number,
        small_item_fee_perkm: smallItemFeePerKM,
        small_item_fee_fixed: smallItemFeeFixed,
        big_item_fee_perkm: bigItemFeePerKM,
        big_item_fee_fixed: bigItemFeeFixed,
        flagdownBigKM: flagdownBigKM,
        flagdownSmallKM: flagdownSmallKM,
        parent_company: parentCompanyId,
      });
    })
    .then(() => {
      res.status(201).json({ success: true });
    })
    .catch((err) => {
      next(err);
    });
};

exports.updateSellersCompany = (req, res, next) => {
  const { data } = req.body;
  const {
    shopName = "",
    shopLocationMunicipality = "",
    shopLocationProvince = "",
    companyName,
    description,
    address,
    latitude,
    longitude,
    owner,
    computationMethod,
    emailAddress,
    contact_number,
    smallItemFeePerKM,
    smallItemFeeFixed,
    bigItemFeePerKM,
    bigItemFeeFixed,
    flagdownBigKM,
    flagdownSmallKM,
  } = data;

  const { sellersCompanyId } = req.params;
  const { sellerLogo } = req.files;

  SellersCompany.findOne({
    where: {
      id: sellersCompanyId,
    },
  })
    .then((sellerCompany) => {
      if (!sellerCompany) {
        return errorHandler("Seller Company ID does not exists!", 404);
      }

      if (sellerLogo && sellerLogo.length > 0) {
        sellerCompany.sellerLogo = sellerLogo[0].filename;
      } else {
        sellerCompany.sellerLogo = null;
      }

      (sellerCompany.company_name = companyName),
        (sellerCompany.shop_name = shopName),
        (sellerCompany.company_description = description),
        (sellerCompany.address = address),
        (sellerCompany.shop_location_municipality = shopLocationMunicipality),
        (sellerCompany.shop_location_province = shopLocationProvince),
        (sellerCompany.latitude = latitude),
        (sellerCompany.longitude = longitude),
        (sellerCompany.owner = owner),
        (sellerCompany.computation_method = computationMethod),
        (sellerCompany.emailAddress = emailAddress),
        (sellerCompany.contact_number = contact_number),
        (sellerCompany.small_item_fee_perkm = smallItemFeePerKM),
        (sellerCompany.small_item_fee_fixed = smallItemFeeFixed),
        (sellerCompany.big_item_fee_perkm = bigItemFeePerKM),
        (sellerCompany.big_item_fee_fixed = bigItemFeeFixed),
        (sellerCompany.flagdownBigKM = flagdownBigKM),
        (sellerCompany.flagdownSmallKM = flagdownSmallKM);

      return sellerCompany.save();
    })
    .then(() => {
      res.status(200).json({ success: true });
    })
    .catch((err) => {
      next(err);
    });
};

exports.deleteSellersCompany = (req, res, next) => {
  const { sellersCompanyId } = req.params;

  SellersCompany.findOne({
    where: {
      id: sellersCompanyId,
    },
  })
    .then((sellerCompany) => {
      if (!sellerCompany) {
        return errorHandler("Seller Company ID does not exists!");
      }
      return sellerCompany.destroy();
    })
    .then(() => {
      res.status(204).send();
    })
    .catch((err) => {
      next(err);
    });
};

exports.findSellersCompanyById = async (req, res, next) => {
  try {
    const { sellersCompanyId } = req.params;

    // Find the seller company by its ID
    const sellerCompany = await SellersCompany.findByPk(sellersCompanyId);
    if (!sellerCompany) {
      return errorHandler("Seller Company ID does not exist!");
    }

    // Find all child companies if the seller company is a parent company
    if (sellerCompany.isParentCompany === "Yes") {
      const childCompanies = await SellersCompany.findAll({
        where: {
          parent_company: sellerCompany.id,
          status: true,
        },
        attributes: ["id", "company_name", "shop_name", "seller_type"],
      });
      sellerCompany.childCompanies = childCompanies.map((child) => ({
        id: child.id,
        companyName: child.company_name,
      }));
    } else if (sellerCompany.isParentCompany === null && sellerCompany.parent_company) {
      const parentCompany = await SellersCompany.findByPk(sellerCompany.parent_company, {
        attributes: ["id", "company_name", "shop_name", "seller_type"],
      });
      if (parentCompany) {
        sellerCompany.parentCompany = {
          id: parentCompany.id,
          companyName:
            parentCompany.shop_name === "" || parentCompany.shop_name === null
              ? parentCompany.company_name
              : parentCompany.shop_name,
        };
      }
    }

    // Calculate the total number of products associated with the seller company
    const productsCount = await Products.count({
      where: {
        seller_id: sellersCompanyId, // Use sellersCompanyId instead of sellerCompanyId
        available: 1,
      },
    });

    // Calculate the average rating for the seller company
    const products = await Products.findAll({
      where: {
        seller_id: sellersCompanyId, // Use sellersCompanyId instead of sellerCompanyId
        available: 1,
      },
      attributes: ["id"],
    });
    const productIds = products.map((product) => product.id);

    const ratings = await DetailProductReviews.findAll({
      where: {
        product_id: productIds,
      },
      attributes: ["rate"],
    });

    const totalRate = ratings.reduce((acc, curr) => acc + curr.rate, 0);
    const averageRating = ratings.length > 0 ? totalRate / ratings.length : 0;

    // Construct the response
    const result = {
      id: sellerCompany.id,
      companyName: sellerCompany.company_name,
      shopName: sellerCompany.shop_name,
      description: sellerCompany.company_description,
      address: sellerCompany.address,
      location: `${sellerCompany.shop_location_municipality}, ${sellerCompany.shop_location_province}`,
      latitude: sellerCompany.latitude,
      longitude: sellerCompany.longitude,
      seller_type: sellerCompany.seller_type,
      owner: sellerCompany.owner,
      sellerLogo: sellerCompany.seller_logo ? `https://buildhub.ph/img/seller/${sellerCompany.seller_logo}` : null,
      banner: sellerCompany.seller_banner_image
        ? `https://buildhub.ph/img/seller/${sellerCompany.seller_banner_image}`
        : null,
      computationMethod: sellerCompany.computation_method,
      emailAddress: sellerCompany.emailAddress,
      contact_number: sellerCompany.contact_number,
      isParentCompany: sellerCompany.isParentCompany,
      smallItemFeePerKM: sellerCompany.smallItemFeePerKM,
      smallItemFeeFixed: sellerCompany.smallItemFeeFixed,
      bigItemFeeFixed: sellerCompany.bigItemFeeFixed,
      bigItemFeePerKM: sellerCompany.bigItemFeePerKM,
      flagdownBigKM: sellerCompany.flagdownBigKM,
      flagdownSmallKM: sellerCompany.flagdownSmallKM,
      averageRating: averageRating,
      totalProducts: productsCount, // Include totalProducts attribute
    };

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

exports.findAllSellersCompany = async (req, res, next) => {
  try {
    const { page, limit, sellerCompanyLimit } = req.pagination;

    const sellerCompanies = await SellersCompany.findAll({
      limit: sellerCompanyLimit,
    });

    if (!sellerCompanies || sellerCompanies.length === 0) {
      return res.status(404).json({ success: false, message: "No seller companies found" });
    }

    const sellerCompanyIds = sellerCompanies.map((company) => company.id);

    const sellers = await Seller.findAll({
      where: {
        seller_id: sellerCompanyIds,
      },
    });

    const sellerIds = sellers.map((seller) => seller.id);

    const productsResult = await Products.findAndCountAll({
      where: {
        seller_id: sellerIds,
      },
      offset: (page - 1) * limit,
      limit: limit,
    });

    const products = productsResult.rows;
    const totalProducts = productsResult.count;

    const sellerCompanyRatings = {};
    await Promise.all(
      sellerCompanies.map(async (company) => {
        const companyProducts = products.filter((product) => sellerIds.includes(product.seller_id));

        const productIds = companyProducts.map((product) => product.id);

        const ratings = await DetailProductReviews.findAll({
          where: {
            product_id: productIds,
          },
          attributes: ["rate"],
        });

        const totalRate = ratings.reduce((acc, curr) => acc + curr.rate, 0);
        const averageRating = ratings.length > 0 ? totalRate / ratings.length : 0;

        sellerCompanyRatings[company.id] = averageRating;
      })
    );

    const result = sellerCompanies.map((company) => {
      const companyProducts = products.filter((product) => sellerIds.includes(product.seller_id));

      const mappedProducts = companyProducts.map((product) => ({
        id: product.id,
        menuId: product.menu_id,
        menu: product.menu,
        variant: product.variant,
        description: product.description,
        price: product.price,
        discountedPrice: product.discounted_price,
        photo: `https://buildhub.ph/img/products/${product.photo}`,
        quantityLimit: product.quantity_limit,
        stocks: product.stocks,
        available: product.available,
        sku: product.sku,
        productVariationId: product.product_variation_id,
        productSubVariationId: product.product_sub_variation_id,
      }));

      return {
        id: company.id,
        name: company.shop_name === "" || company.shop_name === null ? company.company_name : company.shop_name,
        description: company.description,
        address: company.address,
        location: `${company.shop_location_municipality}, ${company.shop_location_province}`,
        logo: company.seller_logo ? `https://buildhub.ph/img/seller/${company.seller_logo}` : null,
        banner: company.seller_banner_image ? `https://buildhub.ph/img/seller/${company.seller_banner_image}` : null,
        emailAddress: company.emailAddress,
        contact_number: company.contact_number,
        isParentCompany: company.isParentCompany,
        longitude: company.longitude,
        latitude: company.latitude,
        products: mappedProducts,
        averageRating: sellerCompanyRatings[company.id], // Include average rating for each seller company
      };
    });

    const totalPages = Math.ceil(totalProducts / limit);
    const hasNextPage = (page - 1) * limit + products.length < totalProducts;
    const hasPreviousPage = page > 1;

    res.status(200).json({
      success: true,
      result,
      pagination: {
        totalPages,
        currentPage: page,
        hasNextPage,
        hasPreviousPage,
      },
    });
  } catch (error) {
    next(error);
  }
};

exports.findProductsBySellersCompany = async (req, res, next) => {
  try {
    const { sellersCompanyId } = req.params;
    const { page, limit } = req.pagination;

    // Find the seller company by its ID
    const sellerCompany = await SellersCompany.findByPk(sellersCompanyId);
    if (!sellerCompany) {
      return res.status(404).json({ success: false, message: "Seller company not found" });
    }

    // Find all sellers associated with the seller company
    const sellers = await Seller.findAll({
      where: {
        seller_id: sellersCompanyId,
      },
      attributes: { exclude: ["email", "password", "username"] },
    });
    const sellerIds = sellers.map((seller) => seller.id);

    // Find all products associated with the seller company
    const productsResult = await Products.findAndCountAll({
      where: {
        seller_id: sellerIds,
      },
      offset: (page - 1) * limit,
      limit: limit,
    });
    const products = productsResult.rows;
    const totalProducts = productsResult.count;

    // Calculate average rating for each product and include it in the response
    const productRatings = {};
    await Promise.all(
      products.map(async (product) => {
        const ratings = await DetailProductReviews.findAll({
          where: {
            product_id: product.id,
          },
          attributes: ["rate"],
        });
        const totalRate = ratings.reduce((acc, curr) => acc + curr.rate, 0);
        const averageRating = ratings.length > 0 ? totalRate / ratings.length : 0;
        productRatings[product.id] = averageRating;
      })
    );

    // Construct the response
    const result = products.map((product) => ({
      id: product.id,
      menuId: product.menu_id,
      menu: product.menu,
      variant: product.variant,
      description: product.description,
      price: product.price,
      discountedPrice: product.discounted_price,
      photo: `https://buildhub.ph/img/products/${product.photo}`,
      quantityLimit: product.quantity_limit,
      stocks: product.stocks,
      available: product.available,
      sku: product.sku,
      productVariationId: product.product_variation_id,
      productSubVariationId: product.product_sub_variation_id,
      seller: sellers.find((seller) => seller.id === product.seller_id),
      sellerCompany: sellerCompany,
      sellerBannerImage: sellerCompany ? `https://buildhub.ph/img/seller/${sellerCompany.seller_banner_image}` : "",
      sellerPhoto: sellerCompany ? `https://buildhub.ph/img/seller/${sellerCompany.seller_logo}` : "",
      rating: productRatings[product.id],
    }));

    const totalPages = Math.ceil(totalProducts / limit);
    const hasNextPage = (page - 1) * limit + products.length < totalProducts;
    const hasPreviousPage = page > 1;

    res.status(200).json({
      success: true,
      result,
      pagination: {
        totalPages,
        currentPage: page,
        hasNextPage,
        hasPreviousPage,
      },
    });
  } catch (error) {
    next(error);
  }
};
