import { useState, useEffect, useContext } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { getNotAvailableDates } from "../services/get-availability"
import fetchUserData from '../custom-hooks/fetch-hook';
import fetchPostData from '../custom-hooks/post-hook';
import { progressTrackerContext } from '../context/progressTrackerContext';
import StepTracker from "./StepTracker";
import NextButton from "./navigation/NextButton";
import BackButton from "./navigation/BackButton";
import { convertFormattedDate, convertFormattedTime, convertIndTimeZone } from "../services/summary-page-utilites";
import ListSkeleton from './skeleton/ListSkeleton';

const Calander = () => {
	const userAppointment = JSON.parse(sessionStorage.getItem("userAppointment")) || {};

	const initialDate = userAppointment.bookedDate ? new Date(userAppointment.bookedDate) : new Date();
	const initialTime = userAppointment.getSelectedTime ? new Date(userAppointment.getSelectedTime) : null;
	const [selectedDate, setSelectedDate] = useState(initialDate);
	const [selectedTime, setSelectedTime] = useState(initialTime);
	const [startDate, setStartDate] = useState(new Date());
	const [blockdates, setBlockDates] = useState([]);
	const [blockTime, setBlockTime] = useState([]);
	const [settings, SetSettings] = useState({});
	const { currentStep, setCurrentStep } = useContext(progressTrackerContext);
	const [formattedDate, setFormattedDate] = useState('');
	const now = new Date();
	const isToday = selectedDate && selectedDate.toDateString() === now.toDateString();
	const [disableNext, setDisableNext] = useState(true);
	const [settingsLoad, setSettingsLoad] = useState(true);
	const [loadDate, setLoadDate] = useState(true);

	// Function to disable weekends based on settings
	const isBlockedDay = (date) => {
		const day = date.getDay(); // 0 = Sunday, 6 = Saturday
		const setting = settings.schedule_on_business_days;

		if (setting === 'all_days_open') {
			return false;
		}

		if (setting === 'sunday_closed') {
			return day === 0;
		}
		if (setting === 'weekends_closed') {
			return day === 0 || day === 6;
		}
		if (setting === 'alternate_saturdays_closed') {
			const dateOfMonth = date.getDate();
			const weekNumber = Math.ceil(dateOfMonth / 7);
			return day === 0 || (day === 6 && (weekNumber === 2 || weekNumber === 4));
		}
		return false;
	};


	useEffect(() => {
		// function to fetch backend settings.
		const fetchUnavailableDates = async () => {
			try {
				const [dates, fieldSettings] = await Promise.all([
					getNotAvailableDates(),
					fetchUserData('ssas/v1/settings-fields', '')
				]);
				SetSettings(fieldSettings);
				// Convert unavailable DB dates to Date objects
				const unavailableDates = dates.map(date => new Date(date));
				// Convert business holidays to Date objects
				const holidays = (fieldSettings.schedule_business_holidays || []).map(dateStr => new Date(dateStr));
				// Merge both arrays
				const mergedDates = [...unavailableDates, ...holidays];
				setBlockDates(mergedDates);
				setSettingsLoad(false);
			} catch (error) {
				console.error('Failed to fetch unavailable dates or settings:', error);
			}
		};
		fetchUnavailableDates();
	}, []);

	useEffect(() => {
		minimumDate();
	}, [settings])

	//Function to skip the past & blocked when on starting dates.
	const minimumDate = () => {
		const nextDate = new Date(startDate);
		if (
			startDate.getHours() >= endTime.getHours() &&
			startDate.getMinutes() >= endTime.getMinutes()
		) {
			nextDate.setDate(nextDate.getDate() + 1);
			while (
				blockdates.some(d => d.toDateString() === nextDate.toDateString()) ||
				isBlockedDay(nextDate)
			) {
				nextDate.setDate(nextDate.getDate() + 1);
			}
			setStartDate(nextDate);
			if (initialDate.getTime() === now.getTime()) {
				setSelectedDate(nextDate);
			}
		}
	};

	//to format the date to user readable.
	useEffect(() => {
		let time = selectedTime ? convertFormattedTime(selectedTime) : 'select a Time';
		let date = convertFormattedDate(selectedDate);
		setFormattedDate(date.concat(" | ", time));

		function disablebtn() {
			if (selectedTime) {
				setDisableNext(false)
			} else {
				setDisableNext(true);
			}
		}
		disablebtn();
	}, [selectedDate, selectedTime])

	//function to convert date to exclude format.
	const parseTimeString = (timeStr) => {
		const [hours, minutes] = timeStr.split(':').map(Number);
		const date = new Date();
		date.setHours(hours, minutes, 0, 0);
		return date;
	};

	//to set start & end time.
	const startTime = settings.schedule_business_hour_start_time
		? parseTimeString(settings.schedule_business_hour_start_time) : (() => {
			const d = new Date(); d.setHours(9, 0, 0, 0);
			return d;
		})();

	const endTime = settings.schedule_business_hour_end_time
		? parseTimeString(settings.schedule_business_hour_end_time) : (() => {
			const d = new Date(); d.setHours(18, 0, 0, 0);
			return d;
		})();

	//set date & time on sessions.
	function handleSubmit() {
		const userAppointment = JSON.parse(sessionStorage.getItem("userAppointment"));
		userAppointment.bookedDate = convertIndTimeZone(selectedDate);
		userAppointment.getSelectedTime = selectedTime;
		userAppointment.bookedTime = selectedTime.toTimeString().split(' ')[0];
		sessionStorage.setItem('userAppointment', JSON.stringify(userAppointment));
		setCurrentStep(currentStep + 1);
	}

	//get the available time based on the date selected.
	useEffect(() => {
		setLoadDate(true);
		const notAvailableTime = async () => {
			const userAppointment = JSON.parse(sessionStorage.getItem("userAppointment"));
			const checkDate = convertIndTimeZone(selectedDate);
			const postArray = {
				categoryid: userAppointment?.specialities,
				usedDate: checkDate,
			};
			const time = await fetchPostData('ssas/v1/categoryid', postArray);
			if (Array.isArray(time?.data)) {
				const blocked = time.data.map(timeStr => {
					const [hours, minutes] = timeStr.split(':').map(Number);
					const dateObj = new Date(selectedDate);
					dateObj.setHours(hours, minutes, 0, 0);
					return dateObj;
				});
				setBlockTime(blocked);
			}
		}
		notAvailableTime();
		const userAppointment = JSON.parse(sessionStorage.getItem("userAppointment"));
		if (new Date(selectedDate).getTime() !== new Date(userAppointment.bookedDate).getTime()) {
			setSelectedTime(null);
		}
	}, [selectedDate])

	useEffect(() => {
		setInterval(() => { setLoadDate(false) }, 1000);
	}, [blockTime, selectedDate])

	let handleExcludeTime = (time) => {
		const timeHour = time.getHours();
		const timeMin = time.getMinutes();
		const startHour = startTime.getHours();
		const startMin = startTime.getMinutes();
		const endHour = endTime.getHours();
		const endMin = endTime.getMinutes();

		// Before start time
		if (timeHour < startHour || (timeHour === startHour && timeMin < startMin)) {
			return "booking-out-of-time";
		}

		// After end time
		if (timeHour > endHour || (timeHour === endHour && timeMin > endMin)) {
			return "booking-out-of-time";
		}

		return "";
	};

	return (
		<div className="inner-booking-block">
			<p className='booking-component-title'>When do you want to come?</p>
			<StepTracker />
			<div className="booking-time-reader-wrapper"><p>{formattedDate}</p></div>
			<div className="booking-component-wrapper booking-calander-wrapper">
				<div className="booking-calander-container">
					<div className="booking-time-picker-wrapper">
						{
							settingsLoad ? <div className="react-datepicker"><ListSkeleton amount={1} /></div> :
								<DatePicker
									selected={selectedDate}
									onChange={(date) => setSelectedDate(date)}
									minDate={startDate} // Disable past dates
									excludeDates={blockdates}
									filterDate={(date) => !isBlockedDay(date)} // Disable weekends
									dateFormat="Pp"
									inline
								/>
						}

					</div>
					<div className="booking-time-picker-wrapper">
						{
							settingsLoad ? <div className="react-datepicker"><ListSkeleton amount={1} /></div> :
								<>
									{
										loadDate ?
											<div className="react-datepicker"><ListSkeleton amount={1} /></div> :
											<DatePicker
												showTimeSelect
												showTimeSelectOnly
												selected={selectedTime}
												excludeTimes={blockTime}
												onChange={(date) => setSelectedTime(date)}
												timeIntervals={settings.schedule_time_slot_interval ? settings.schedule_time_slot_interval : 30}
												inline
												minTime={isToday && now > startTime ? now : startTime} // Disable past time on the current day
												maxTime={isToday && now > endTime ? now : endTime} // Set maximum time
												timeClassName={handleExcludeTime}
											/>
									}
								</>
						}

					</div>
				</div>
				<div className='booking-nav-buttons'>
					<NextButton styles={`booking-nav-next ${disableNext ? 'disabled' : ''}`} onClick={handleSubmit} innerText={"What's Next"} />
					<BackButton styles="booking-nav-back" onClick={() => setCurrentStep(currentStep - 1)} />
				</div>
			</div>
		</div>
	);
}

export default Calander
