'use strict';
const ezeeHelper = require('../helpers/ezeeHelper');
const dotenv = require("dotenv").config();
const HotelCode = process.env.EZEE_HOTEL_CODE;
const APIKey = process.env.EZEE_API_KEY;
const availability_request_type = 'RoomList';
const property = require("../models/propertyModel");
const Property = new property;
const collection = require("../models/collectionModel");
const { request } = require('express');
const User = require('../models/userModel');
const Collection = new collection();
const booking = require("../models/bookingModel");
const Booking = new booking;
const settingHelper = require("../helpers/settingsHelper");
const SettingsHelper = new settingHelper();
const Response = require("../helpers/responseHelper");

const { format,addDays,differenceInMilliseconds,getTime, eachDayOfInterval,differenceInDays,isBefore,isPast,subDays } = require("date-fns");

class AvailabilityController{
    constructor(ezeeHelper){
        this.ezeeHelper = ezeeHelper;
    }

    async availabilityParams(inputs,forDetailsPage = false){
        var {check_in_date, check_out_date, destination,number_adults, number_children,home,collection,propertyId } = inputs;
        if(!check_in_date){
            check_in_date = format(new Date(), 'yyyy-MM-dd');
            check_out_date = format(addDays(new Date(), 2),'yyyy-MM-dd');
            if(!forDetailsPage){
                home = 1;
            }   
        }
        if(!check_out_date){
            check_out_date = format(addDays(check_in_date, 2),'yyyy-MM-dd');
        }
        if(!number_adults || number_adults == 0){
            number_adults = 2;
        }
        if(!number_children){
            number_children = 0; 
        }
        if(!forDetailsPage){
            if(!destination){
                destination = 1;
            }
        }
        return {check_in_date, check_out_date, destination,number_adults, number_children,home,collection,propertyId };
    }

    async home(req,res){
        try {
            const method = 'GET';
            const params = {
                request_type:availability_request_type,
                HotelCode: HotelCode,
                APIKey: APIKey,
                check_in_date: format(new Date(), 'yyyy-MM-dd'),
                check_out_date: format(addDays(new Date(), 2),'yyyy-MM-dd'),
                number_adults:2,
                number_children:0,
                destination:1
            }
            const results = await this.ezeeHelper.fetchData('reservation_api/listing.php', method, params);

            if(!results || results.length == 0){
                return Response.error(res, "NO_PROPERTIES_AVAILABLE", "No properties available", 400);
            }
            var properties = await Property.listPropertiesDetails({destination:1});
            
            var availableProperties = await this.ezeePropertyParameters(results,properties);
            var propertiesByCollection = await this.propertiesByCollection(properties);
            properties = await Property.listPropertiesDetails({featured:1});
            var featuredProperties = properties.map(a => a.id);
            var userFavourites = {};
            if(req.guest){
                var favourites = await Property.userFavourites(req.guest.id);
                userFavourites = favourites.map(a => a.property_id);
            }
            const formSettings = await SettingsHelper.formSettings();
            const settings = await SettingsHelper.consolidatedSettings();
            return Response.success(res, "Availability data retrieved successfully", {available:availableProperties,featured:featuredProperties,
                propertiesByCollection:propertiesByCollection, favourites:userFavourites,formSettings:formSettings,settings:settings});
        } catch (error) {
            console.error(error);
            return Response.error(res, "INTERNAL_SERVER_ERROR", "Internal server error", 500);
        }
    }

    async find(req,res){
        try {
            console.log("find");
            console.log(req.body);
            const {check_in_date, check_out_date, destination,number_adults, number_children } = req.body;
            var adjustedParams = await this.availabilityParams(req.body);
            const method = 'GET';
            const params = {
                request_type:availability_request_type,
                HotelCode: HotelCode,
                APIKey: APIKey,
                check_in_date: adjustedParams.check_in_date,
                check_out_date: adjustedParams.check_out_date,
                number_adults:adjustedParams.number_adults,
                number_children:adjustedParams.number_children,
                destination:adjustedParams.destination,
                collection:adjustedParams.collection
            }
            var filters = {};
            if(req.body.propertyId || req.body.slug){
                var property;
                if(req.body.propertyId){
                    property = await Property.getById(req.body.propertyId);
                }else{
                    property = await Property.getBySlug(req.body.slug);
                }
                if(property[0]){
                    params['roomtypeunkid'] = property[0].channel_id;
                    filters['id'] = req.body.propertyId;
                }else{
                   return Response.error(res, "PROPERTY_NOT_FOUND", "Property does not exist", 400);
                }   
            }
            if(adjustedParams.destination){
                filters['destination'] = adjustedParams.destination;
            }
            if(adjustedParams.collection){
                filters['collection'] = adjustedParams.collection;
            }
            var homePageRequest = false;
            if(adjustedParams.home && adjustedParams.home == 1){
                homePageRequest = true;
            }
            const results = await this.ezeeHelper.fetchData('reservation_api/listing.php', method, params);

            if(!results || results.length == 0){
                return Response.error(res, "NO_PROPERTIES_AVAILABLE", "No properties available", 400);
            }
            if(!homePageRequest){
                var availableResults = await results.filter(res => res.min_ava_rooms > 0);
                filters['channelIds'] = await availableResults.map(item => `'${item.roomtypeunkid}'`).join(',');
            }
            var properties = await Property.listPropertiesDetails(filters);
            
            var availableProperties = await this.ezeePropertyParameters(results,properties);
            var propertiesByCollection = await this.propertiesByCollection(properties);
            properties = await Property.listPropertiesDetails({featured:1});
            var featuredProperties = properties.map(a => a.id);
            var userFavourites = {};
            if(req.guest){
                var favourites = await Property.userFavourites(req.guest.id);
                userFavourites = favourites.map(a => a.property_id);
            }
           return Response.success(res, "Availability data retrieved successfully", {available:availableProperties,featured:featuredProperties,
                propertiesByCollection:propertiesByCollection, favourites:userFavourites});
        } catch (error) {
            console.error(error);
            return Response.error(res, "INTERNAL_SERVER_ERROR", "Internal server error", 500);
        }
    }

    async propertiesByCollection(properties){        
        var propertiesByCollection = {};
        var collections = properties.flatMap(p => p.collections);
        var activeCollections = await Collection.activeCollections();
        collections = collections.filter(function(col){
            if(activeCollections.includes(col)){
                return col;
            }
        });
        collections = collections.filter(function(item, pos){
            return collections.indexOf(item)== pos;
        });
        collections.forEach(collection => {
            var props = properties.filter(property => property.collections.includes(collection));
            propertiesByCollection[collection] = props.map(a => a.id);
        });
        return propertiesByCollection;
    }

    async ezeePropertyParameters(results,filteredProperties){
        var properties = [];
        var webDiscount = await SettingsHelper.webDiscount();
        results.forEach(ezeeProp => {
            var dbProp = filteredProperties.find(p => p.channel_id == ezeeProp.roomtypeunkid);
            if(!dbProp){
                return;
            }
            var property = {};
            property["id"] = dbProp.id;
            property["display_order"] = dbProp.display_order;
            property["channel_id"] = dbProp.channel_id;
            property["listing_name"] = dbProp.listing_name;
            property["slug"] = dbProp.slug;
            property["destination"] = dbProp.destination;
            property["display_image"] = dbProp.display_image;
            property["featured_property"] = dbProp.featured_property;
            property["bedrooms"] = dbProp.number_of_bedrooms;
            property["bathrooms"] = dbProp.number_of_bathrooms;
            property["pool"] = dbProp.pool;
            property["max_capacity"] = parseInt(ezeeProp.base_adult_occupancy) + parseInt(ezeeProp.base_child_occupancy);
            property["price_per_night"] = Math.round(ezeeProp.room_rates_info.avg_per_night_without_tax * (100 - webDiscount)/100);
            //favorite
            property["totalprice_room_only"] = Math.round(ezeeProp.room_rates_info.totalprice_room_only);
            property["totalprice_inclusive_all"] = ezeeProp.room_rates_info.totalprice_inclusive_all;
            property["property_type"] = dbProp.property_type;
            property["amenities"] = dbProp.amenitiesWithDescriptions;
            property["collections"] = dbProp.collections;
            property["medias"] = dbProp.medias;
            properties.push(property);
        });
        properties.sort((a,b)=>a.display_order - b.display_order);
        return properties;
    }

    async calendarAvailabilityForProperty(req,res){
        var {propertyId} = req.body;
        var dbProperty = await Property.getBySlug(propertyId);
        var property = await this.calendarAvailability_v3(dbProperty[0].channel_id);
        if(property == null){
           return Response.error(res, "PROPERTY_NOT_AVAILABLE", "Property not available", 400);
        }
        return Response.success(res, "Calendar availability retrieved successfully", {property: property});
    }

    async calendarAvailability_v2(check_in_date, check_out_date, propertyId){
        var calendar = {};
        const days = eachDayOfInterval({start: check_in_date,end: check_out_date});
        var formattedDay;
        var availability = 0;//unavailable
        for(let day in days){
            formattedDay = format(days[day],'yyyy-MM-dd');
            if(!isBefore(formattedDay,format(new Date(),'yyyy-MM-dd'))){
                availability = 1;//availablle
            }
            calendar[formattedDay] = availability;
        }
        
        if(isBefore(check_in_date,format(new Date(),'yyyy-MM-dd'))){
            check_in_date = format(new Date(),'yyyy-MM-dd');
        }
        const booked = await Booking.calendarAvailability(check_in_date,check_out_date,propertyId);
        booked.forEach(book=>{
            calendar[book.EffectiveDate] = 0;
        });
        return calendar;
    }

    async calendarAvailability_v3(propertyId){
        var calendar = {};
        const results = await Booking.futureOccupiedDates(propertyId);
        results.forEach(result=>{
            calendar[result.EffectiveDate] = 0;
        });
        return calendar;
    }

    async pricingAndDetails(req,res){
        try {
            const {check_in_date, check_out_date, propertyId,number_adults, number_children,slug } = req.body;
            console.log('pricingAndDetails request:', { propertyId, slug, check_in_date, check_out_date, number_adults, number_children });
            
            if(!propertyId && !slug){
                res.status(400).json({ success: false, error: "Mandatory parameters propertyId is missing!" });
                return;
            }
            if(!propertyId){

            }
            /* Get property details from DB */
            var filters = {};
            if(propertyId){
                filters['id'] = propertyId;
            }else{
                filters['slug'] = slug;
            }
            
            console.log('Searching for property with filters:', filters);
            var properties = await Property.listPropertiesDetails(filters);
            console.log('Found properties:', properties.length, properties.map(p => ({ id: p.id, slug: p.slug, listing_name: p.listing_name })));
            
            var dbProp = properties.find(p => p.id == propertyId || p.slug == slug);
            if(!dbProp){//no property is found for the propertyId
                console.log('Property not found in database');
           return Response.error(res, "PROPERTY_NOT_AVAILABLE", "Property not available", 400);
            }

            console.log('Found property in database:', { id: dbProp.id, slug: dbProp.slug, channel_id: dbProp.channel_id, listing_name: dbProp.listing_name });
            
            var adjustedParams = await this.availabilityParams(req.body,true);
            const params = {
                check_in_date: adjustedParams.check_in_date,
                check_out_date: adjustedParams.check_out_date,
                roomtypeunkid:dbProp.channel_id
            }
            console.log('Calling Ezee with params:', params);
            var result = await this.ezeeHelper.getProperty(params);
            console.log('Ezee response:', result);
            var ezeeProp = result.property;
            if(!ezeeProp || ezeeProp == null){
                console.log('Ezee property not found or null - proceeding with database property only');
                // If Ezee is not available or property doesn't exist in Ezee, 
                // we can still show the property with basic information
                dbProp["max_adults_allowed"] = dbProp.number_of_guests || 2;
                dbProp["max_children_allowed"] = dbProp.number_of_extra_guests || 0;
                dbProp["adults"] = adjustedParams.number_adults;
                dbProp["child"] = adjustedParams.number_children;
                dbProp["price_per_night"] = 0; // No pricing available
                dbProp["totalprice_room_only"] = 0;
                dbProp["totalprice_inclusive_all"] = 0;
                dbProp["min_ava_rooms"] = 0; // Not available
                dbProp["ezee_available"] = false; // Flag to indicate Ezee data not available
                
                // Return the property with basic information
                return Response.success(res, "Property found but pricing not available", dbProp);
            }
            
            dbProp["max_adults_allowed"] = ezeeProp.max_adult_occupancy;
            dbProp["max_children_allowed"] = ezeeProp.max_child_occupancy;
            dbProp["adults"] = adjustedParams.number_adults;
            dbProp["child"] = adjustedParams.number_children;
            if(adjustedParams.number_adults > ezeeProp.max_adult_occupancy || adjustedParams.number_children > ezeeProp.max_child_occupancy){
                /* Doesn't accommodate that many*/
                return Response.error(res, "PROPERTY_NOT_AVAILABLE", "Not available for the search criteria", 400);
            }
            if(!check_in_date || !check_out_date){
                //if no dates specified, then don't give out prices
                return Response.success(res, "Dates not specified", dbProp);
            }
            var number_of_nights = ((new Date(check_out_date)).getTime() - (new Date(check_in_date)).getTime())/ (1000 * 60 * 60 * 24); 
            dbProp["number_of_nights"] = number_of_nights;
            if(ezeeProp.min_ava_rooms == 0){
                return Response.error(res, "PROPERTY_NOT_AVAILABLE", "Not available for the selected dates", 400);
            }

            dbProp["price_per_night"] = ezeeProp.room_rates_info.avg_per_night_without_tax;
            dbProp = await this.pricingCalcs(ezeeProp,number_adults,number_children,dbProp);
            return Response.success(res, "Property details retrieved successfully", dbProp);
        } catch (error) {
            console.error(error);
            return Response.error(res, "INTERNAL_ERROR", error.message, 500);
        }
    }

    async pricingCalcs(ezeeProp,number_adults,number_children,property){
        var webDiscount = await SettingsHelper.webDiscount();
        var extraAdults = number_adults - parseInt(ezeeProp.base_adult_occupancy);
        var extraChildren = number_children - parseInt(ezeeProp.base_child_occupancy);
        
        //var totalprice_room_only = ezeeProp.room_rates_info.totalprice_room_only;
        //var totalprice_inclusive_all = ezeeProp.room_rates_info.totalprice_inclusive_all;
        var extra_adults_charges = 0;
        var extra_children_charges = 0;
        var price_per_night = Math.round(ezeeProp.room_rates_info.avg_per_night_without_tax * (100-webDiscount)/100);
        var gstRate = price_per_night <= 7500 ? 0.05 : 0.18;
        var totalTaxes = price_per_night * property["number_of_nights"] * gstRate;
        if(extraAdults > 0){
            Object.values(ezeeProp.extra_adult_rates_info.exclusive_tax).forEach(value => {
                //totalprice_room_only +=  extraAdults * value;
                extra_adults_charges += extraAdults * value;
            });
            Object.values(ezeeProp.extra_adult_rates_info.inclusive_tax_adjustment).forEach(value => {
                //totalprice_inclusive_all += extraAdults * value;
                //totalTaxes += extraAdults * value;
            });
        }
        if(extraChildren > 0){
            Object.values(ezeeProp.extra_child_rates_info.exclusive_tax).forEach(value => {
                //totalprice_room_only +=  extraChildren * value;
                extra_children_charges += extraChildren * value;
            });
            Object.values(ezeeProp.extra_child_rates_info.inclusive_tax_adjustment).forEach(value => {
                //totalprice_inclusive_all += extraChildren * value;
                //totalTaxes += extraChildren * value;
            });
        }
        totalTaxes += (extra_adults_charges + extra_children_charges) * gstRate;
        //var total_taxes = totalprice_inclusive_all - totalprice_room_only;
        property["price_per_night"] = price_per_night + (extra_adults_charges + extra_children_charges)/property["number_of_nights"];
        property["extra_person_charges_per_night"] = (extra_adults_charges + extra_children_charges)/property["number_of_nights"];
        //property["totalprice_room_only"] = totalprice_room_only;
        //property["total_taxes"] = total_taxes;
        //property["totalprice_inclusive_all"] = totalprice_inclusive_all;
        property["total_taxes"] = totalTaxes;
        property["totalprice_room_only"] = price_per_night * property["number_of_nights"];
        property["totalprice_inclusive_all"] = price_per_night * property["number_of_nights"] + extra_adults_charges + extra_children_charges + totalTaxes;
        return property;
    }

    async findByDates(req, res){
        try{
            const method = 'GET';
            const params = {
                request_type:'RoomTypeList',
                HotelCode:'40583',
                APIKey: APIKey
            }
            const result = await this.ezeeHelper.fetchData('reservation_api/listing.php', method, params);
            const roomtypeunkidList = result.map(item => item.roomtypeunkid).join(',');
            return Response.success(res, "Room types retrieved successfully", result);
        }catch(error){
            console.error(error);
            return Response.error(res, "INTERNAL_ERROR", error.message, 500);
        }
    }

    async pricingInfo(req,res){
        try{
            const {start, end, property_id} = req.body;
            var property = await Property.getById(property_id);
            if(!property[0]){
                return Response.error(res, "PROPERTY_NOT_FOUND", "Property does not exist", 400);
            }
            var ezeeProp = await this.ezeeHelper.getProperty({check_in_date:start, check_out_date:end, roomtypeunkid:property[0].channel_id});
            if(!ezeeProp || ezeeProp == null){
                return Response.error(res, "PROPERTY_NOT_AVAILABLE", "Property not available", 400);
            }
            const rates = ezeeProp.property.room_rates_info.exclusive_tax;
            return Response.success(res, "Pricing information retrieved successfully", rates);
        }catch(error){
            console.error(error);
            return Response.error(res, "INTERNAL_ERROR", error.message, 500);
        }
    }

    async datesByProperty(req,res){
        const { year, month, propertyId } = req.query;
        try {
            if (!propertyId) {
                return Response.error(res, "PROPERTY_ID_REQUIRED", "Property ID is required", 400);
            }

            const unavailableRanges = await Booking.propertyCalendar(propertyId); // Fetch from DB
            return Response.success(res, "Unavailable dates retrieved successfully", unavailableRanges);
        } catch (error) {
            return Response.error(res, "INTERNAL_ERROR", error.message, 500);
        }
    }
}
module.exports = AvailabilityController;