const { Op } = require('sequelize');
const { parseJsonSafe } = require('../../helpers');
const {
  createHostRegistration,
  updateUserStatus,
  checkUserStatus,
  findHostRegistrationById,
  approveHostRegistration,
  createListing,
  saveListingImages,
  updateUserHostStatus,
  createListingAddOns,
} = require('../../services');
const { errorHandler } = require('../../util');
const { Listings, ListingFiles, ListingImages } = require('../../models');
const { checkManagerAccess } = require('../../helpers/managers');

exports.applyHost = (req, res, next) => {
  const { userId } = req;
  const { data } = req.body;

  checkUserStatus(userId)
    .then(() => {
      return createHostRegistration(userId, data, req.files);
    })
    .then((newUser) => {
      return updateUserStatus(userId).then(() => newUser);
    })
    .then(() => {
      return res.status(201).json({ success: true });
    })
    .catch((err) => {
      next(err);
    });
};

exports.getMyApplications = async (req, res, next) => {
  const { status, search } = req.query;

  let hostId = req.userId;
  if (req.query.hostId) {
    hostId = (await checkManagerAccess(req)).hostId;
  }

  const filter = {
    host_id: hostId,
    status: { [Op.ne]: 'Approved' },
  };

  if (status && status !== 'Approved') {
    filter.status = status;
  }

  if (search) {
    filter[Op.or] = [
      { listing_name: { [Op.like]: `%${search}%` } },
      { listing_description: { [Op.like]: `%${search}%` } },
      { location_address: { [Op.like]: `%${search}%` } },
    ];
  }

  Listings.findAll({
    where: filter,
    include: [
      {
        model: ListingImages,
        as: 'listingImages',
        limit: 1,
      },
    ],
  })
    .then((applications) => {
      const mappedData = applications.map((application) => ({
        id: application.id,
        listingName: application.name,
        description: application.description,
        location: application.location,
        status: application.status,
        image: application.listingImages
          ? application.listingImages.map((image) => ({
              image: `${process.env.BASE_URL}/public/host-uploads/${image.image}`,
            }))
          : [],
      }));

      return res.status(200).json({
        success: true,
        data: mappedData,
      });
    })
    .catch((err) => {
      next(err);
    });
};

exports.approveApplication = (req, res, next) => {
  const { applicationId } = req.params;

  findHostRegistrationById(applicationId)
    .then((hostRegistration) => {
      if (!hostRegistration) {
        return errorHandler('Application not found.', 404);
      }

      if (hostRegistration.status === 'Approved') {
        return errorHandler('Application has already been approved.', 400);
      }

      return approveHostRegistration(applicationId)
        .then(() =>
          createListing({
            host_id: hostRegistration.user_id,
            name: hostRegistration.listing_name,
            description: hostRegistration.listing_description,
            location_type: JSON.parse(hostRegistration.location_type),
            address_country: hostRegistration.address_country,
            address_street: hostRegistration.address_street,
            address_apt: hostRegistration.address_apt,
            address_city: hostRegistration.address_city,
            address_state: hostRegistration.address_state,
            address_zip: hostRegistration.address_zip,
            longitude: hostRegistration.location_long,
            latitude: hostRegistration.location_lat,
            price: hostRegistration.individual_rate,
            min_capacity: 1,
            max_capacity: hostRegistration.capacity,
            amenities: JSON.parse(hostRegistration.amenities),
            services: JSON.parse(hostRegistration.services),
            check_in_time: hostRegistration.check_in_time,
            check_out_time: hostRegistration.check_out_time,
            cancellation_policy: hostRegistration.cancellation_policy,
          }),
        )
        .then((listing) =>
          saveListingImages(listing.id, hostRegistration.files).then(() => listing),
        )
        .then((listing) => createListingAddOns(listing.id, hostRegistration.id))
        .then(() => updateUserHostStatus(hostRegistration.user_id));
    })
    .then(() => {
      res.status(200).json({
        success: true,
        message: 'Application has been approved successfully.',
      });
    })
    .catch((err) => {
      next(err);
    });
};

exports.getApplicationById = (req, res, next) => {
  const { userId } = req;
  const { applicationId } = req.params;

  const filter = {
    user_id: userId,
    id: applicationId,
  };

  HostsRegistrations.findOne({
    where: filter,
    include: [
      {
        model: HostRegistrationFiles,
        as: 'files',
        attributes: ['file_type', 'file'],
      },
    ],
  })
    .then((application) => {
      if (!application) {
        return res.status(404).json({
          success: false,
          message: 'Application not found',
        });
      }

      const mappedData = {
        application: {
          id: application.id,
          cityToHost: application.city_to_hosts,
          listingName: application.listing_name,
          description: application.listing_description,
          duration: application.duration,
          location: {
            type: parseJsonSafe(application.location_type),
            address: application.location_address,
            lat: application.location_lat,
            long: application.location_long,
          },
          amenities: parseJsonSafe(application.amenities),
          services: parseJsonSafe(application.services),
          checkInTime: application.check_in_time,
          checkOutTime: application.check_out_time,
          cancellationPolicy: application.cancellation_policy,
          selfieImage: `${process.env.BASE_URL}/public/host-uploads/${application.selfie_image}`,
          status: application.status,
        },
        files: application.files
          ? application.files.map((file) => ({
              fileType: file.file_type,
              file: `${process.env.BASE_URL}/public/host-uploads/${file.file}`,
            }))
          : [],
      };

      return res.status(200).json({
        success: true,
        data: mappedData,
      });
    })
    .catch((err) => {
      next(err);
    });
};
