/**
 * QueueManager: Handles the hybrid slot logic for Curio
 * - 30-min slots
 * - Max 3 online bookings (Hard Cap)
 * - 5 Walk-in slots
 */

const configManager = require('./configManager');
const notificationManager = require('./notificationManager');

class QueueManager {
    constructor() {
        this.slots = {}; // Key: "tenantId:YYYY-MM-DD:HH:mm"
    }

    getSlotKey(tenantId, date, time) {
        const config = configManager.getTenantConfig(tenantId);
        const duration = config.slotDuration || 30;
        const [hours, minutes] = time.split(':');
        const roundedMins = parseInt(minutes) < duration ? '00' : duration;
        return `${tenantId}:${date}:${hours}:${roundedMins}`;
    }

    isAvailable(tenantId, date, time) {
        const config = configManager.getTenantConfig(tenantId);
        const d = new Date(date + "T00:00:00");
        
        // Check days off
        if (config.daysOff && config.daysOff.includes(d.getDay())) return false;
        
        // Check holidays
        if (config.holidays && config.holidays.includes(date)) return false;

        // Check working hours
        if (config.workingHours) {
            const [h, m] = time.split(':').map(Number);
            const timeVal = h * 60 + m;
            
            const isInRange = config.workingHours.some(range => {
                const [sH, sM] = range.start.split(':').map(Number);
                const [eH, eM] = range.end.split(':').map(Number);
                const startVal = sH * 60 + sM;
                const endVal = eH * 60 + eM;
                return timeVal >= startVal && timeVal < endVal;
            });
            
            if (!isInRange) return false;
        }

        return true;
    }

    getSlotStatus(tenantId, date, time) {
        const key = this.getSlotKey(tenantId, date, time);
        if (!this.slots[key]) {
            const config = configManager.getTenantConfig(tenantId);
            this.slots[key] = { 
                online: 0, 
                walkin: 0, 
                maxOnline: config.onlineSlotLimit || 3, 
                maxWalkin: config.walkinSlotLimit || 5 
            };
        }
        return this.slots[key];
    }

    bookOnline(date, time, tenantId = 'default') {
        if (!this.isAvailable(tenantId, date, time)) {
            return { success: false, message: "The clinic is closed at this time / on this day." };
        }
        const status = this.getSlotStatus(tenantId, date, time);
        const config = configManager.getTenantConfig(tenantId);
        if (status.online < status.maxOnline) {
            status.online++;
            return { 
                success: true, 
                token: `ON-${status.online}`, 
                slot: this.getSlotKey(tenantId, date, time),
                status: 'PENDING_PAYMENT',
                fee: config.consultationFee
            };
        }
        return { success: false, message: "Slot full for online booking. Try next slot." };
    }

    bookWalkin(date, time, tenantId = 'default') {
        if (!this.isAvailable(tenantId, date, time)) {
            return { success: false, message: "The clinic is closed at this time / on this day." };
        }
        const status = this.getSlotStatus(tenantId, date, time);
        const config = configManager.getTenantConfig(tenantId);
        if (status.walkin < status.maxWalkin) {
            status.walkin++;
            return { 
                success: true, 
                token: `WK-${status.walkin}`,
                status: 'PENDING_PAYMENT',
                fee: config.consultationFee
            };
        }
        return { success: false, message: "Clinic is at full capacity for this slot." };
    }

    getDailyUpdates(patientId, tenantId = 'default') {
        const config = configManager.getTenantConfig(tenantId);
        return [
            `Good morning! Your appointment with ${config.name} is scheduled for today.`,
            "Queue Update: The clinic is running 10 mins behind schedule. Please plan accordingly.",
            "Reminder: Don't forget to bring your previous reports."
        ];
    }

    cancelBooking(date, time, tenantId = 'default') {
        const status = this.getSlotStatus(tenantId, date, time);
        if (status.online > 0) {
            status.online--;
            this.notifyAvailableSlot(tenantId, date, time);
            return { success: true, message: "Booking cancelled and slot opened." };
        }
        return { success: false, message: "No bookings found for this slot." };
    }

    notifyAvailableSlot(tenantId, date, time) {
        const config = configManager.getTenantConfig(tenantId);
        console.log(`[Queue] Triggering notifications for open slot: ${time}`);
        
        // Mock finding a patient with a later slot
        const mockLaterPatient = { phone: "9876543210", appointmentTime: "19:00" };
        
        notificationManager.sendRescheduleAlert(
            mockLaterPatient.phone,
            config.name,
            mockLaterPatient.appointmentTime,
            time
        );
    }

    rescheduleBooking(date, oldTime, newTime, tenantId = 'default') {
        const newSlotStatus = this.getSlotStatus(tenantId, date, newTime);
        const oldSlotStatus = this.getSlotStatus(tenantId, date, oldTime);

        // Atomic Check: Ensure new slot hasn't been filled since notification
        if (newSlotStatus.online < newSlotStatus.maxOnline) {
            newSlotStatus.online++;
            if (oldSlotStatus.online > 0) {
                oldSlotStatus.online--;
            }
            return { 
                success: true, 
                message: `✅ *Success!* Your appointment has been moved to *${newTime}*. Your old slot at ${oldTime} has been released.` 
            };
        }
        return { 
            success: false, 
            message: "❌ *Slot Already Taken*: Sorry, another patient claimed that earlier slot just before you. You still have your original appointment at " + oldTime + "." 
        };
    }
}

module.exports = new QueueManager();
