const express = require('express');
const joi = require('joi');
const Campaign = require('../models/Campaign');
const { auth, requireActivePlan } = require('../middleware/auth');
const checkLimit = require('../middleware/limit-checker');

const router = express.Router();

// 1. List Campaigns
// 1. List Campaigns
router.get('/', auth, async (req, res) => {
    try {
        let query = {};
        if (!req.user.isSuperAdmin) {
            query = { createdBy: req.user._id };
        }

        const campaigns = await Campaign.find(query)
            .populate('agentId', 'name')
            .sort({ createdAt: -1 });

        res.status(200).json({
            status: 'success',
            results: campaigns.length,
            data: { campaigns }
        });
    } catch (err) {
        res.status(500).json({ status: 'error', message: err.message });
    }
});

// 2. Get One Campaign
router.get('/:id', auth, async (req, res) => {
    try {
        const query = { _id: req.params.id };
        if (!req.user.isSuperAdmin) {
            query.createdBy = req.user._id;
        }

        const [campaign, callLogs] = await Promise.all([
            Campaign.findOne(query)
                .populate('agentId')
                .populate('leadIds'),
            require('../models/CallLog').find({ campaignId: req.params.id })
        ]);

        if (!campaign) {
            return res.status(404).json({ status: 'error', message: 'Campaign not found' });
        }

        res.status(200).json({
            status: 'success',
            data: {
                campaign,
                callLogs
            }
        });
    } catch (err) {
        res.status(500).json({ status: 'error', message: err.message });
    }
});

// 3. Create Campaign
router.post('/', auth, requireActivePlan, checkLimit('campaigns'), async (req, res) => {
    const schema = joi.object({
        name: joi.string().required(),
        agentId: joi.string().required(),
        leadIds: joi.array().items(joi.string()).required()
    });

    try {
        const value = await schema.validateAsync(req.body);
        const campaign = new Campaign({
            ...value,
            createdBy: req.user._id,
            status: 'idle'
        });
        await campaign.save();

        res.status(201).json({
            status: 'success',
            data: { campaign }
        });
    } catch (err) {
        res.status(400).json({ status: 'error', message: err.message });
    }
});

// 4. Start Campaign
router.post('/:id/start', auth, requireActivePlan, checkLimit('calls'), async (req, res) => {
    try {
        const query = { _id: req.params.id };
        if (!req.user.isSuperAdmin) {
            query.createdBy = req.user._id;
        }
        const campaign = await Campaign.findOne(query)
            .populate('leadIds');

        if (!campaign) {
            return res.status(404).json({ status: 'error', message: 'Campaign not found' });
        }

        if (campaign.status === 'running') {
            return res.status(400).json({ status: 'error', message: 'Campaign is already running' });
        }

        const settings = await require('../models/Settings').findOne();
        if (!settings || !settings.twilioSid || !settings.twilioToken || !settings.fromNumber) {
            return res.status(400).json({ status: 'error', message: 'Twilio credentials not configured' });
        }

        // Update status to running
        campaign.status = 'running';
        await campaign.save();

        const twilio = require('twilio');
        const client = twilio(settings.twilioSid, settings.twilioToken);
        const baseUrl = process.env.BASE_URL || `http://${req.get('host')}`;

        // Respond immediately
        res.status(200).json({
            status: 'success',
            started: true,
            message: 'Campaign execution sequence initiated'
        });

        // Background Processor
        setImmediate(async () => {
            console.log(`[Campaign Engine] Executing: ${campaign.name}`);

            for (const lead of campaign.leadIds) {
                console.log(`[Campaign Engine] Calling: ${lead.name} (${lead.phone})`);

                try {
                    const call = await client.calls.create({
                        url: `${baseUrl}/api/twilio/voice?userId=${req.user._id}&agentId=${campaign.agentId._id || campaign.agentId}&leadId=${lead._id}&campaignId=${campaign._id}`,
                        to: lead.phone,
                        from: settings.fromNumber,
                        record: settings.recordingEnabled ?? true,
                        statusCallback: `${baseUrl}/api/twilio/status`,
                        statusCallbackMethod: 'POST',
                        statusCallbackEvent: ['initiated', 'ringing', 'answered', 'completed']
                    });

                    // Create successful initial CallLog
                    await require('../models/CallLog').create({
                        campaignId: campaign._id,
                        leadId: lead._id,
                        agentId: campaign.agentId._id || campaign.agentId,
                        userId: req.user._id,
                        callSid: call.sid,
                        status: 'queued',
                        startTime: new Date()
                    });
                } catch (callError) {
                    console.error(`[Campaign Engine] Failed to call ${lead.phone}:`, callError.message);

                    // Create a failed CallLog record so campaign progress isn't stalled
                    await require('../models/CallLog').create({
                        campaignId: campaign._id,
                        leadId: lead._id,
                        agentId: campaign.agentId._id || campaign.agentId,
                        userId: req.user._id,
                        callSid: `failed-${Date.now()}-${lead._id}`,
                        status: 'failed',
                        startTime: new Date()
                    });
                }
            }

            console.log(`[Campaign Engine] All calls triggered for: ${campaign.name}`);
        });

    } catch (err) {
        res.status(500).json({ status: 'error', message: err.message });
    }
});

// 5. Stop Campaign
router.post('/:id/stop', auth, async (req, res) => {
    try {
        const query = { _id: req.params.id };
        if (!req.user.isSuperAdmin) {
            query.createdBy = req.user._id;
        }
        const campaign = await Campaign.findOne(query);

        if (!campaign) {
            return res.status(404).json({ status: 'error', message: 'Campaign not found' });
        }

        if (campaign.status !== 'running') {
            return res.status(400).json({ status: 'error', message: 'Campaign is not running' });
        }

        const settings = await require('../models/Settings').findOne();
        if (!settings || !settings.twilioSid || !settings.twilioToken) {
            return res.status(400).json({ status: 'error', message: 'Twilio credentials not configured' });
        }

        // Update status to stopped
        campaign.status = 'stopped';
        await campaign.save();

        const CallLog = require('../models/CallLog');
        const activeLogs = await CallLog.find({
            campaignId: campaign._id,
            status: { $in: ['queued', 'ringing', 'in-progress', 'initiated'] }
        });

        const twilio = require('twilio');
        const client = twilio(settings.twilioSid, settings.twilioToken);

        // Cancel active calls in Twilio
        const cancelPromises = activeLogs.map(async (log) => {
            try {
                await client.calls(log.callSid).update({ status: 'completed' }); // 'completed' is used to hang up active calls
                await CallLog.findByIdAndUpdate(log._id, { status: 'canceled' });
            } catch (err) {
                console.error(`Failed to cancel call ${log.callSid}:`, err.message);
            }
        });

        await Promise.all(cancelPromises);

        res.status(200).json({
            status: 'success',
            message: 'Campaign stopped and active calls terminated'
        });

    } catch (err) {
        res.status(500).json({ status: 'error', message: err.message });
    }
});

// 6. Delete Campaign
router.delete('/:id', auth, async (req, res) => {
    try {
        const query = { _id: req.params.id };
        if (!req.user.isSuperAdmin) {
            query.createdBy = req.user._id;
        }
        const campaign = await Campaign.findOne(query);

        if (!campaign) {
            return res.status(404).json({ status: 'error', message: 'Campaign not found' });
        }

        if (campaign.status === 'running') {
            return res.status(400).json({ status: 'error', message: 'Cannot delete a running campaign. Please stop it first.' });
        }

        await Campaign.findByIdAndDelete(req.params.id);

        res.status(200).json({
            status: 'success',
            message: 'Campaign deleted successfully'
        });
    } catch (err) {
        res.status(500).json({ status: 'error', message: err.message });
    }
});

// 7. Bulk Delete Campaigns
router.post('/bulk-delete', auth, async (req, res) => {
    try {
        const { ids } = req.body;
        if (!ids || !Array.isArray(ids)) {
            return res.status(400).json({ status: 'error', message: 'Invalid or missing campaign IDs' });
        }

        const query = {
            _id: { $in: ids },
            status: 'running'
        };
        if (!req.user.isSuperAdmin) {
            query.createdBy = req.user._id;
        }

        const runningCount = await Campaign.countDocuments(query);

        if (runningCount > 0) {
            return res.status(400).json({ status: 'error', message: 'Cannot delete running campaigns. Please stop them first.' });
        }

        const deleteQuery = { _id: { $in: ids } };
        if (!req.user.isSuperAdmin) {
            deleteQuery.createdBy = req.user._id;
        }

        await Campaign.deleteMany(deleteQuery);

        res.status(200).json({
            status: 'success',
            message: 'Campaigns deleted successfully'
        });
    } catch (err) {
        res.status(500).json({ status: 'error', message: err.message });
    }
});

module.exports = router;
