const { Op } = require("sequelize");
const {
  Property,
  Address,
  PropertyFeatures,
  User,
  PayOnAccess,
  Feedback,
  Bookmark,
  PropertyImages,
  Report,
  Plan,
} = require("../../models");
const { getReqInformation, getSettings } = require("../../utils/Common");
const {
  PropertyFeature,
  PropertyStatus,
  PropertyTypes,
  PropertyFurnishing,
  Reports,
  States,
  PropertyKind,
} = require("../../utils/Constants");
const { addAddress, updateAddress } = require("../api/AddressController");
const {
  deletePropertyFeature,
  addPropertyFeature,
} = require("../api/PropertyFeatureController");
const { addImage } = require("./PropertyImageController");
const { getLatLongByAddress } = require("../../utils/GoogleMap");
const sequelize = require("../../utils/Connection");

const index = async (req, res) => {
  let user = req.session?.user ?? {};
  let { baseUrl, endPoint } = getReqInformation(req);
  let query = { propertyStatus: 1 };
  let payload = req.query;
  if (payload?.status) {
    query["status"] = payload?.status;
  }
  if (payload?.type) {
    query["type"] = payload?.type;
  }

  if (payload?.price) {
    query["price"] = {
      [Op.lte]: payload?.price,
    };
  }

  let addressQuery = {};

  if (payload?.location) {
    addressQuery = {
      [Op.or]: [
        {
          city: {
            [Op.like]: `%${payload?.location}%`,
          },
        },
        {
          street: {
            [Op.like]: `%${payload?.location}%`,
          },
        },
        {
          state: {
            [Op.like]: `%${payload?.location}%`,
          },
        },
      ],
    };
  }

  let lat = 0,
    long = 0,
    radius = 25;
  if (payload?.lat && payload?.long) {
    lat = payload?.lat;
    long = payload?.long;
  } else if (req.session.location?.lat && req.session.location?.long) {
    lat = req.session.location?.lat ?? 0;
    long = req.session.location?.long ?? 0;
  }
  let properties = [];
  if (lat && long) {
    let xyz = `(6371 * acos(cos(radians(${lat})) * cos(radians(address.latitude)) * cos(radians(address.longitude) - radians(${long})) + sin(radians(${lat})) * sin(radians(address.latitude))))`;
    properties = await Property.findAll({
      where: query,
      order: [["featured", "desc"]],
      include: [
        {
          model: Address,
          attributes: [
            "id",
            "street",
            "city",
            "postalCode",
            "state",
            "latitude",
            "longitude",
            [sequelize.literal(xyz), "distance"],
          ],
          where: addressQuery,
        },
        {
          model: PropertyFeatures,
          attributes: ["key", "value"],
        },
        {
          model: User,
          attributes: ["firstName", "lastName"],
        },
      ],
      having: sequelize.where(sequelize.literal(xyz), "<", radius),
    });
  } else {
    properties = await Property.findAll({
      where: query,
      order: [["featured", "desc"]],
      include: [
        {
          model: Address,
          attributes: [
            "id",
            "street",
            "city",
            "postalCode",
            "state",
            "latitude",
            "longitude",
          ],
          where: addressQuery,
        },
        {
          model: PropertyFeatures,
          attributes: ["key", "value"],
        },
        {
          model: User,
          attributes: ["firstName", "lastName"],
        },
      ],
    });
  }

  let bookmarks = [];
  if (req.session?.user) {
    bookmarks = await Bookmark.findAll({
      where: {
        userId: req?.session?.user?.id,
      },
    });
  }

  let settings = await getSettings();
  return res.render("properties/index.ejs", {
    baseUrl,
    endPoint,
    properties,
    PropertyFeature,
    PropertyStatus,
    PropertyFurnishing,
    PropertyTypes,
    PropertyKind,
    oldFilterData: payload ?? {},
    user,
    settings,
    bookmarks,
  });
};

const getById = async (req, res) => {
  let user = req.session?.user ?? {};
  let { baseUrl, endPoint } = getReqInformation(req);
  let id = req.params?.id;
  console.log(req.params, "=-=-=-=");
  let settings = await getSettings();
  let feedbacks = await Feedback.findAll({
    where: {
      propertyId: id,
    },
    include: [
      {
        model: User,
        attributes: ["firstName", "lastName", "image"],
      },
    ],
  });
  let property = await Property.findOne({
    where: {
      id: id,
    },
    order: [["featured", "desc"]],
    include: [
      {
        model: Address,
      },
      {
        model: PropertyFeatures,
        attributes: ["key", "value"],
      },
      {
        model: User,
        attributes: ["firstName", "lastName", "email", "mobileNo", "image"],
      },
      {
        model: PropertyImages,
        attributes: ["id", "path"],
      },
    ],
  });

  if (property && !property?.user) {
    property.user = {
      firstName: "Admin",
      lastName: "",
      mobileNo: settings?.contactInfoMobileNo ?? "",
      email: settings?.contactInfoEmail ?? "",
    };
  }
  property.payonaccess = null;
  if (req?.session?.user) {
    if (req.session?.user?.planActivationDate) {
      property.payonaccess = { userId: req.session.user?.id };
    } else {
      let payOnAccess = await PayOnAccess.findOne({
        where: {
          propertyId: property?.id,
          userId: user?.id,
        },
      });
      property.payonaccess = payOnAccess || null;
    }
  }
  return res.render("properties/property-by-id.ejs", {
    baseUrl,
    endPoint,
    property,
    PropertyFeature,
    user,
    settings,
    feedbacks,
    Reports,
  });
};

const addProperty = async (req, res) => {
  let user = req.session?.user ?? {},
    property = {},
    id = req.params?.id;
  let { baseUrl, endPoint } = getReqInformation(req);
  let successMessage = req.flash("success")[0];
  let errorMessage = req.flash("error")[0];
  let settings = await getSettings();
  if (id) {
    property = await Property.findOne({
      where: {
        id: id,
        userId: user?.id,
      },
      order: [["featured", "desc"]],
      include: [
        {
          model: Address,
        },
        {
          model: PropertyFeatures,
          attributes: ["key", "value"],
        },
        {
          model: User,
          attributes: ["firstName", "lastName", "email", "mobileNo"],
        },
        {
          model: PropertyImages,
          attributes: ["propertyId", "id", "path"],
        },
      ],
    });
    if (!property) {
      req.flash("error", "Something went wrong!!");
      return res.redirect("/");
    }
  }
  return res.render("properties/add-property.ejs", {
    baseUrl,
    endPoint,
    PropertyFurnishing,
    PropertyStatus,
    PropertyTypes,
    PropertyKind,
    PropertyFeature,
    user,
    successMessage,
    errorMessage,
    property,
    settings,
    States,
  });
};

const addPropertyProcess = async (req, res) => {
  try {
    let payload = req.body,
      id = payload?.id;
    const { baseUrl } = getReqInformation(req);
    payload["userId"] = req?.session?.user?.id;
    let address = {
      street: payload?.street,
      city: payload?.city,
      state: payload?.state,
      postalCode: payload?.postalCode,
    };
    let addressData = `${address.street},${address.city},${address.state},${address.postalCode},IN`;
    let detail = await getLatLongByAddress(addressData);
    address["latitude"] = detail.latitude;
    address["longitude"] = detail.longitude;
    let msg = "Property added successfully",
      url = "/properties/add-property";
    if (req.files) {
      payload["image"] = baseUrl + "/uploads/" + req.files[0]?.filename;
    }
    if (payload?.id) {
      delete payload.id;
      await updateAddress(payload?.addressId, address);
      msg = "Property updated successfully";
      await Property.update(payload, {
        where: {
          id: id,
        },
      });
      url = "/properties/add-property/" + id;
    } else {
      let addedAddress = await addAddress(address);
      payload["addressId"] = addedAddress?.id;
      let property = await Property.create(payload);
      id = property.id;
    }

    console.log(id, "-=-=-=-");
    if (req?.files?.length) {
      await Promise.all(
        req.files?.map(async (file) => {
          let image = baseUrl + "/uploads/" + file?.filename;
          await addImage({ propertyId: id, path: image });
        })
      );
    }

    let propertyFeatures = [];
    PropertyFeature.map((feature) => {
      if (payload[feature.id] && payload[feature.id] != "") {
        propertyFeatures.push({ key: feature.id, value: payload[feature.id] });
      }
    });
    await deletePropertyFeature(id);
    propertyFeatures?.map(async (feature) => {
      feature["propertyId"] = id;
      await addPropertyFeature(feature);
    });
    req.flash("success", msg);
    return res.redirect(url);
  } catch (err) {
    console.log(err);
    req.flash("error", "Something went wrong!!");
    return res.redirect("/properties/add-property");
  }
};

const initiatePayment = async (req, res) => {
  try {
    let payload = req.body;
    payload["userId"] = req.session?.user?.id;
    await PayOnAccess.create(payload);
    req.flash("success", "You have paid amount to see property details.");
    return res.redirect("/properties/" + req.body?.propertyId);
  } catch (err) {
    req.flash("error", "Something went wrong!!");
    return res.redirect("/properties/" + req.body?.propertyId);
  }
};

const myProperties = async (req, res) => {
  try {
    let user = req.session?.user;
    const { baseUrl, endPoint } = getReqInformation(req);
    let settings = await getSettings();
    let userId = req?.session?.user?.id;
    let successMessage = req.flash("success")[0];
    let errorMessage = req.flash("error")[0];
    let properties = await Property.findAll({
      where: {
        userId: userId,
      },
      include: [
        {
          model: Address,
        },
        {
          model: PropertyFeatures,
          attributes: ["key", "value"],
        },
        {
          model: User,
          attributes: ["firstName", "lastName"],
        },
      ],
    });
    return res.render("properties/my-properties.ejs", {
      properties,
      user,
      settings,
      baseUrl,
      endPoint,
      successMessage,
      errorMessage,
    });
  } catch (err) {
    req.flash("error", "Something went wrong!!");
    return res.redirect("/");
  }
};

const deleteImage = async (req, res) => {
  try {
    let { propertyId, id } = req.params;
    await PropertyImages.destroy({
      where: {
        propertyId: propertyId,
        id: id,
      },
    });
    req.flash("success", "Image deleted successfully!!");
    return res.redirect("/properties/add-property/" + req.params?.propertyId);
  } catch (err) {
    req.flash("error", "Something went wrong!!");
    return res.redirect("/properties/add-property/" + req.params?.propertyId);
  }
};

const report = async (req, res) => {
  try {
    let payload = req.body;
    payload["userId"] = req.session?.user?.id;
    await Report.create(payload);
    return res.redirect("/properties/" + req.body?.propertyId);
  } catch (err) {
    return res.redirect("/properties/" + req.body?.propertyId);
  }
};

const deleteProperty = async (req, res) => {
  try {
    let id = req.params.propertyId;
    let property = await Property.findOne({
      where: {
        id: id,
        userId: req?.session?.user?.id,
      },
    });
    if (!property) {
      req.flash("error", "Property id is wrong!!");
      return res.redirect("/properties/my-properties");
    }
    await Address.destroy({
      where: {
        id: property.addressId,
      },
    });
    await PropertyFeatures.destroy({
      where: {
        propertyId: id,
      },
    });
    await Bookmark.destroy({
      where: {
        propertyId: id,
      },
    });
    await PropertyImages.destroy({
      where: {
        propertyId: id,
      },
    });
    property.destroy();
    req.flash("success", "Property deleted successfully!!");
    return res.redirect("/properties/my-properties");
  } catch (err) {
    req.flash("error", "Something went wrong!!");
    return res.redirect("/properties/my-properties");
  }
};

module.exports = {
  index,
  getById,
  addProperty,
  addPropertyProcess,
  initiatePayment,
  myProperties,
  deleteImage,
  report,
  deleteProperty,
};
