const Dispatch = require('../models/Dispatch');
const AmbulanceRequest = require('../models/AmbulanceRequest');
const Driver = require('../models/Driver');
const Notification = require('../models/Notification');
const User = require('../models/User');
const { sendPushToUser } = require('../config/push');
const { sendDispatchEmail, sendDeveloperNotificationEmail } = require('../config/email');

const buildPushErrorSummary = (userId, error) => ({
    user_id: userId,
    attempted: 0,
    sent: 0,
    failed: 0,
    skipped: true,
    reason: 'unexpected-error',
    error: error?.message || String(error)
});

const dispatchController = {
    // Create dispatch (assigns ambulance and driver to request)
    create: (req, res, sendNotification = () => {}, broadcastDispatch = () => {}) => {
        const notify = typeof sendNotification === 'function' ? sendNotification : () => {};
        const broadcast = typeof broadcastDispatch === 'function' ? broadcastDispatch : () => {};
        const { request_id, ambulance_id, driver_id } = req.body;

        const createNotificationRecord = (userId, text) => new Promise((resolve) => {
            if (!userId || !text) {
                return resolve(null);
            }
            Notification.create({ user_id: userId, text }, (err, result) => {
                if (err) {
                    console.error('Failed to persist notification:', err.message);
                    return resolve({ error: err.message });
                }
                resolve({ id: result.insertId, user_id: userId, text });
            });
        });

        if (!request_id || !ambulance_id || !driver_id) {
            return res.status(400).json({ 
                error: 'Missing required fields: request_id, ambulance_id, and driver_id are required' 
            });
        }

        // Check if request exists
        AmbulanceRequest.findRequestById(request_id, (err, requestResults) => {
            if (err) {
                return res.status(500).json({ error: err.message });
            }
            if (requestResults.length === 0) {
                return res.status(404).json({ error: 'Ambulance request not found' });
            }

            const requesterUserId = requestResults[0].request_by;
            // Check if dispatch already exists for this request
            Dispatch.findByRequestId(request_id, (err, dispatchResults) => {
                if (err) {
                    return res.status(500).json({ error: err.message });
                }
                if (dispatchResults.length > 0) {
                    return res.status(400).json({ error: 'Dispatch already exists for this request' });
                }

                // Create dispatch record
                Dispatch.create({
                    ambulance_request_id: request_id,
                    ambulance_id,
                    driver_id
                }, (err, dispatchResults) => {
                    if (err) {
                        if (err.code === 'ER_DUP_ENTRY') {
                            return res.status(400).json({ error: 'Dispatch already exists for this request' });
                        }
                        if (err.code === 'ER_NO_REFERENCED_ROW_2') {
                            return res.status(400).json({ error: 'Invalid ambulance ID or driver ID' });
                        }
                        return res.status(500).json({ error: err.message });
                    }

                    // Update request status to 'dispatched'
                    AmbulanceRequest.updateStatus(request_id, 'dispatched', null, (err, updateResults) => {
                        if (err) {
                            // Rollback: delete dispatch if status update fails
                            Dispatch.delete(dispatchResults.insertId, () => {});
                            return res.status(500).json({ error: err.message });
                        }

                        // Get the created dispatch with related data
                        Dispatch.findById(dispatchResults.insertId, (err, dispatchData) => {
                            if (err) {
                                return res.status(500).json({ error: err.message });
                            }

                            const dispatchRecord = dispatchData[0];
                            let driverUserId = null;

                            // Notify the assigned driver in real-time
                            Driver.findById(driver_id, (driverErr, driverResults) => {
                                let driverPushPromise = Promise.resolve(null);

                                if (!driverErr && driverResults.length) {
                                    driverUserId = driverResults[0].user_id;
                                    notify(driverUserId, {
                                        type: 'driver-assigned',
                                        request_id,
                                        ambulance_id,
                                        driver_id,
                                        dispatch_id: dispatchRecord.id,
                                        status: 'dispatched',
                                        message: 'You have been assigned a new dispatch'
                                    });

                                    driverPushPromise = sendPushToUser(driverUserId, {
                                        notification: {
                                            title: 'New Dispatch',
                                            body: 'You have been assigned a new ambulance dispatch'
                                        },
                                        data: {
                                            type: 'driver-assigned',
                                            request_id: String(request_id),
                                            ambulance_id: String(ambulance_id),
                                            driver_id: String(driver_id),
                                            dispatch_id: String(dispatchRecord.id)
                                        }
                                    }).catch((err) => {
                                        console.error('Failed to send push notification to driver:', err.message);
                                        return buildPushErrorSummary(driverUserId, err);
                                    });

                                    // Persist driver notification for in-app feed
                                    Notification.create(
                                        {
                                            user_id: driverUserId,
                                            request_id,
                                            text: `You have been assigned to ambulance request #${request_id}. Dispatch ID: ${dispatchRecord.id}.`,
                                        },
                                        (notifErr) => {
                                            if (notifErr) {
                                                console.error('Failed to save driver notification:', notifErr.message);
                                            }
                                        }
                                    );
                                } else if (driverErr) {
                                    console.error('Failed to load driver for push notification:', driverErr.message);
                                }

                                // Notify the requester that their ambulance was dispatched
                                notify(requesterUserId, {
                                    type: 'request-dispatched',
                                    request_id,
                                    ambulance_id,
                                    driver_id,
                                    dispatch_id: dispatchRecord.id,
                                    status: 'dispatched',
                                    message: 'Your ambulance request has been dispatched'
                                });

                                const requesterPushPromise = sendPushToUser(requesterUserId, {
                                    notification: {
                                        title: 'Ambulance Dispatched',
                                        body: 'Your ambulance request has been dispatched'
                                    },
                                    data: {
                                        type: 'request-dispatched',
                                        request_id: String(request_id),
                                        ambulance_id: String(ambulance_id),
                                        driver_id: String(driver_id),
                                        dispatch_id: String(dispatchRecord.id)
                                    }
                                }).catch((err) => {
                                    console.error('Failed to send push notification to requester:', err.message);
                                    return buildPushErrorSummary(requesterUserId, err);
                                });

                                // Persist notifications for audit/history
                                const requesterNotificationText = `Your ambulance request #${request_id} has been dispatched. Dispatch ID: ${dispatchRecord.id}.`;
                                const driverNotificationText = `You have been assigned to ambulance request #${request_id}. Dispatch ID: ${dispatchRecord.id}.`;
                                const requesterNotificationPromise = createNotificationRecord(requesterUserId, requesterNotificationText);
                                const driverNotificationPromise = driverUserId ? createNotificationRecord(driverUserId, driverNotificationText) : Promise.resolve(null);

                                // Send email to client when ambulance is dispatched
                                const clientEmailPromise = new Promise((resolve) => {
                                    User.findById(requesterUserId, (userErr, userResults) => {
                                        if (!userErr && userResults.length > 0) {
                                            const user = userResults[0];
                                            const clientEmail = user.email;
                                            const clientName = `${user.first_name} ${user.last_name}`;
                                            const requestData = requestResults[0];
                                            
                                            sendDispatchEmail(clientEmail, clientName, {
                                                request_id,
                                                ambulance_id,
                                                driver_id,
                                                dispatch_id: dispatchRecord.id,
                                                location: requestData.location,
                                                destination: requestData.destination
                                            }).then((result) => {
                                                resolve({ sent: true, email: clientEmail, result });
                                            }).catch((emailErr) => {
                                                console.error('Failed to send dispatch email to client:', emailErr.message);
                                                resolve({ error: emailErr.message, skipped: true, email: clientEmail });
                                            });
                                        } else if (userErr) {
                                            console.error('Failed to load user for dispatch email:', userErr.message);
                                            resolve({ error: userErr.message, skipped: true });
                                        } else {
                                            resolve({ skipped: true, reason: 'User not found' });
                                        }
                                    });
                                });

                                // Broadcast to websocket subscribers (global stream)
                                broadcast({
                                    request_id,
                                    ambulance_id,
                                    driver_id,
                                    dispatch_id: dispatchRecord.id,
                                    status: 'dispatched',
                                    timestamp: new Date().toISOString(),
                                });

                                // Broadcast that request is assigned (removed from pending) to all drivers
                                const broadcastAssigned = req.broadcastRequestAssigned || (() => {});
                                broadcastAssigned(Number(request_id), {
                                    dispatch_id: dispatchRecord.id,
                                    ambulance_id,
                                    driver_id
                                });

                                Promise.all([
                                    driverPushPromise,
                                    requesterPushPromise,
                                    requesterNotificationPromise,
                                    driverNotificationPromise,
                                    clientEmailPromise,
                                    // Send email notification to developers concurrently
                                    sendDeveloperNotificationEmail('dispatched', requestResults[0]).catch(err => {
                                        console.error('Failed to send developer notification for dispatch:', err.message);
                                    })
                                ]).then(
                                    ([driverPush, requesterPush, requesterNotification, driverNotification, clientEmail]) => {
                                        res.status(201).json({
                                            message: 'Dispatch created successfully and request status updated to dispatched',
                                            dispatch: dispatchRecord,
                                            push_delivery: {
                                                driver: driverPush,
                                                requester: requesterPush
                                            },
                                            notifications: {
                                                requester: requesterNotification,
                                                driver: driverNotification
                                            },
                                            email: {
                                                client: clientEmail
                                            }
                                        });
                                    }
                                );
                            });
                        });
                    });
                });
            });
        });
    },

    // Cancel dispatch
    cancel: (req, res) => {
        const { request_id } = req.body;

        if (!request_id) {
            return res.status(400).json({ error: 'request_id is required' });
        }

        // Check if request exists
        AmbulanceRequest.findRequestById(request_id, (err, requestResults) => {
            if (err) {
                return res.status(500).json({ error: err.message });
            }
            if (requestResults.length === 0) {
                return res.status(404).json({ error: 'Ambulance request not found' });
            }

            // Check if dispatch exists
            Dispatch.findByRequestId(request_id, (err, dispatchResults) => {
                if (err) {
                    return res.status(500).json({ error: err.message });
                }

                // Delete dispatch record if it exists
                if (dispatchResults.length > 0) {
                    Dispatch.deleteByRequestId(request_id, (err, deleteResults) => {
                        if (err) {
                            return res.status(500).json({ error: err.message });
                        }

                        // Update request status to 'cancelled'
                        AmbulanceRequest.updateStatus(request_id, 'cancelled', null, (err, updateResults) => {
                            if (err) {
                                return res.status(500).json({ error: err.message });
                            }

                            res.json({
                                message: 'Dispatch cancelled successfully and request status updated to cancelled'
                            });
                        });
                    });
                } else {
                    // No dispatch record, just update status
                    AmbulanceRequest.updateStatus(request_id, 'cancelled', null, (err, updateResults) => {
                        if (err) {
                            return res.status(500).json({ error: err.message });
                        }

                        res.json({
                            message: 'Request status updated to cancelled (no dispatch record found)'
                        });
                    });
                }
            });
        });
    },

    // Get all dispatches
    getAll: (req, res) => {
        Dispatch.findAll((err, results) => {
            if (err) {
                return res.status(500).json({ error: err.message });
            }
            res.json(results);
        });
    },

    // Get dispatch by request ID
    getByRequestId: (req, res) => {
        const requestId = req.params.requestId;
        Dispatch.findByRequestId(requestId, (err, results) => {
            if (err) {
                return res.status(500).json({ error: err.message });
            }
            if (results.length === 0) {
                return res.status(404).json({ message: 'Dispatch not found for this request' });
            }
            res.json(results[0]);
        });
    }
};

module.exports = dispatchController;

