const { Admin, ManagerOwed, MiscLog, MiscTxn } = require('../models/Associations')
const ShortShift = require('../models/ShortShift');

const { Op, fn, col } = require('sequelize');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const axios = require('axios');
const date = require('date-and-time');
const db = require('../config/db.config');
const moment = require('moment-timezone');
// const jwt = require('jsonwebtoken');
const mysql = require('mysql2/promise');
const fs = require('fs');
const path = require('path');
const sharp = require('sharp');
const { v4: uuidv4 } = require('uuid');

require('dotenv').config()

const sendSMS = async (phone, otp) => {
    const url = 'https://swback.logiclane.tech/api/sms';
    const payload = {
        phone: phone,
        message: 'Your SweepStake Mobi verification code is: ' + otp
    };

    try {
        const response = await axios.post(url, payload, {
            headers: {
                'Content-Type': 'application/json',
                'Authorization': 'Bearer 4d0f394ec46be1c61d203a4df09da3277aa8c520d922533bf332c7db2c261f61'
            }
        });
        console.log('SMS sent successfully:', response.data);
    } catch (error) {
        console.error('Error sending SMS:', error.response ? error.response.data : error.message);
    }
};

exports.dashboard = async (req, res) => {
    try {
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        const managers = await Admin.findAll({
            where:
            {
                role: { [Op.in]: ['Super', 'Manager'] },
                ban: '0'
            },
            attributes: { exclude: ['password'] }
        });
        const manager_owed = await ManagerOwed.findOne({ where: { manager_id: admin.id }, order: [['id', 'desc']] })
        const miscs = await MiscLog.findOne();

        let init = 0;
        let owed = 0;
        let manager = 0;
        if (admin.role == 'Manager' && manager_owed) {
            manager = 1;
            owed = manager_owed.amount;
        }
        if (miscs) {
            init = 1;
        }
        return res.json({ status: 'success', data: { miscs, init, managers, owed, manager } })


    } catch (error) {
        if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(error);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}

exports.fillBalance = async (req, res) => {
    const { amount } = req.body;
    if (!amount) {
        return res.status(200).json({ status: 'error', message: 'Amount is missing' });
    }
    try {
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        const miscLog = await MiscLog.findOne();

        if (!miscLog) {
            return res.status(200).json({ error: 'Misc not found' });
        }

        const fillAmount = parseFloat(amount);
        const prevBalance = parseFloat(miscLog.initial_amount);
        const newBalance = prevBalance + fillAmount;

        const log = await MiscTxn.create({
            admin_id: admin.id,
            initial_balance: miscLog.initial_amount,
            prev_balance: prevBalance,
            fill_balance: fillAmount,
            fill_only: '1',
            new_balance: newBalance
        });

        miscLog.admin_id = admin.id;
        await miscLog.increment('initial_amount', { by: fillAmount }); // assuming column is 'initial_balance'
        await miscLog.save();

        return res.json({ status: 'success', message: 'Fill Amount Set' });
    } catch (error) {
        if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(error);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}

exports.resetPos = async (req, res) => {
    try {
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }

        await MiscLog.destroy({ where: {}, truncate: true });
        await MiscTxn.destroy({ where: {}, truncate: true });
        await ShortShift.destroy({ where: {}, truncate: true });
        await ManagerOwed.destroy({ where: {}, truncate: true });

        return res.json({ status: 'success', message: 'POS Reset Successful' })
    } catch (error) {
        if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(error);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}

exports.initialBalance = async (req, res) => {
    const { amount } = req.body;
    if (!amount) {
        return res.status(200).json({ status: 'error', message: 'Amount is missing' });
    }
    try {
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        const parsedAmount = parseFloat(amount)
        await MiscLog.create({
            admin_id: admin.id,
            initial_amount: parsedAmount
        })
        await MiscTxn.create({
            admin_id: admin.id,
            initial_balance: parsedAmount,
            new_balance: parsedAmount
        })

        return res.json({ status: 'success', message: 'Initial Balance Set' })

    } catch (error) {
        if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(error);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}

// exports.saveWithdraw = async (req, res) => {
//     try {
//         const authHeader = req.headers['authorization'] || req.headers['Authorization'];
//         if (!authHeader) {
//             return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
//         }

//         const token = authHeader.split(' ')[1];
//         if (!token) {
//             return res.status(200).json({ status: 'error', message: 'Token is missing' });
//         }

//         const decoded = jwt.verify(token, process.env.JWT_SECRET);
//         const adminId = decoded.id;

//         const admin = await Admin.findOne({ where: { id: adminId } });
//         if (!admin) {
//             return res.status(200).json({ error: 'Admin not found' });
//         }

//         const { withamount, withreason, manager } = req.body;
//         const image = req.file;

//         if (!image) {
//             return res.status(200).json({ status: 'error', message: 'Image is required' });
//         }

//         const amount = parseFloat(withamount);
//         const miscLog = await MiscLog.findOne();
//         if (!miscLog) return res.status(200).json({ status: 'error', message: 'MiscLog not found' });

//         let managerOwed = null;
//         let managerx = null;

//         if (manager) {
//             managerOwed = await ManagerOwed.findOne({ where: { manager_username: manager } });
//             managerx = await Admin.findOne({ where: { username: manager } });
//         }

//         const evidenceDir = path.join(__dirname, '../public/evidence');
//         if (!fs.existsSync(evidenceDir)) fs.mkdirSync(evidenceDir, { recursive: true });

//         const uuid = uuidv4();
//         let savedFile = '';
//         let isAvif = false;

//         try {
//             // Try saving AVIF
//             const avifPath = path.join(evidenceDir, `${uuid}.avif`);
//             await sharp(image.buffer).toFormat('avif').toFile(avifPath);
//             savedFile = `${uuid}.avif`;
//             isAvif = true;
//         } catch (e) {
//             // Fallback to original format
//             const ext = path.extname(image.originalname).toLowerCase();
//             const fallbackPath = path.join(evidenceDir, `${uuid}${ext}`);
//             await sharp(image.buffer).toFile(fallbackPath);
//             savedFile = `${uuid}${ext}`;
//         }

//         // Update misc log
//         await miscLog.update({
//             admin_id: admin.id,
//             withdraw_reason: withreason,
//             withdraw_amount: amount,
//             withdraw_manager: manager || null
//         });

//         if (manager) {
//             if (managerOwed) {
//                 await managerOwed.increment('amount', { by: amount });
//             } else {
//                 await ManagerOwed.create({
//                     manager_id: managerx.id,
//                     manager_username: managerx.username,
//                     amount: amount
//                 });
//             }
//         }

//         const managerAmount = managerOwed ? parseFloat(managerOwed.amount) + parseFloat(amount) : amount;

//         await MiscTxn.create({
//             admin_id: admin.id,
//             initial_balance: miscLog.initial_amount,
//             withdraw_balance: amount,
//             withdraw_reason: withreason,
//             withdraw_document: savedFile,
//             withdraw_manager: manager || null,
//             with_only: '1',
//             manager_owed: managerAmount,
//             prev_balance: miscLog.initial_amount,
//             new_balance: parseFloat(miscLog.initial_amount) - parseFloat(amount)
//         });

//         if (amount) {
//             await miscLog.decrement('initial_amount', { by: amount });
//         }

//         return res.json({ status: 'success', message: 'Withdraw Amount Set' });
//     } catch (err) {
//         if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
//             return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
//         }

//         console.error(err);
//         res.status(200).json({ status: 'error', message: 'Internal server error' });
//     }
// }
exports.saveWithdraw = async (req, res) => {
    try {
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }

        const { withamount, withreason, manager } = req.body;
        const image = req.file;
        if (!image) {
            return res.status(200).json({ status: 'error', message: 'Image is required' });
        }

        const amount = parseFloat(withamount);
        const miscLog = await MiscLog.findOne();
        if (!miscLog) return res.status(200).json({ status: 'error', message: 'MiscLog not found' });

        const evidenceDir = path.join(__dirname, '../public/evidence');
        if (!fs.existsSync(evidenceDir)) fs.mkdirSync(evidenceDir, { recursive: true });

        const uuid = uuidv4();
        const ext = path.extname(image.originalname).toLowerCase();
        const originalFile = `${uuid}${ext}`;
        const savePath = path.join(evidenceDir, originalFile);

        // Save image immediately
        fs.writeFileSync(savePath, image.buffer);

        let managerOwed = null;
        let managerx = null;
        if (manager) {
            [managerOwed, managerx] = await Promise.all([
                ManagerOwed.findOne({ where: { manager_username: manager } }),
                Admin.findOne({ where: { username: manager } })
            ]);
        }

        await miscLog.update({
            admin_id: admin.id,
            withdraw_reason: withreason,
            withdraw_amount: amount,
            withdraw_manager: manager || null
        });

        if (manager) {
            if (managerOwed) {
                await managerOwed.increment('amount', { by: amount });
            } else {
                await ManagerOwed.create({
                    manager_id: managerx.id,
                    manager_username: managerx.username,
                    amount: amount
                });
            }
        }

        const managerAmount = managerOwed ? parseFloat(managerOwed.amount) + amount : amount;

        await MiscTxn.create({
            admin_id: admin.id,
            initial_balance: miscLog.initial_amount,
            withdraw_balance: amount,
            withdraw_reason: withreason,
            withdraw_document: originalFile,
            withdraw_manager: manager || null,
            with_only: '1',
            manager_owed: managerAmount,
            prev_balance: miscLog.initial_amount,
            new_balance: parseFloat(miscLog.initial_amount) - amount
        });

        await miscLog.decrement('initial_amount', { by: amount });

        // Send success response early
        res.json({ status: 'success', message: 'Withdraw Amount Set' });

        // ---- Background AVIF conversion ----
        const avifPath = path.join(evidenceDir, `${uuid}.avif`);
        sharp(image.buffer)
            .toFormat('avif')
            .toFile(avifPath)
            .then(async () => {
                console.log(`AVIF version saved: ${avifPath}`);
                // await MiscTxn.update(
                //     { withdraw_document: `${uuid}.avif` },  // Update with AVIF version
                //     { where: { withdraw_document: originalFile } }  // Find the record by the original file name
                // );

                // fs.unlinkSync(savePath);
                // console.log('MiscTxn updated with AVIF image.');
            })
            .catch(err => {
                console.warn('AVIF conversion failed:', err.message);
            });

    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
};
exports.saveShortShift = async (req, res) => {
    const { amount } = req.body;
    if (!amount) {
        return res.status(200).json({ status: 'error', message: 'Amount is missing' });
    }
    try {
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ status: 'success', message: 'Admin not found' });
        }

        const lastTxn = await MiscTxn.findOne({
            where: {
                with_only: { [Op.ne]: 1 },
                fill_only: { [Op.ne]: 1 }
            },
            order: [['id', 'DESC']]
        });

        const lastAdmin = await Admin.findByPk(lastTxn.admin_id);

        const insert = await ShortShift.create({
            current_admin: admin.id,
            last_admin: lastAdmin.id,
            amount: amount,
            created_at: new Date(),
            updated_at: new Date()
        });

        if (!insert) throw new Error('Short shift insert failed');

        const log = await MiscLog.findOne();
        if (!log) return res.status(200).json({ status: 'success', message: 'MiscLog not found' });

        await log.decrement('initial_amount', { by: amount });

        await axios.post('https://bend.logiclane.tech/api/sms', {
            phone: lastAdmin.phone,
            message: `Hi ${lastAdmin.username}, You are short by $${amount}, It will be deducted from your next pay-check.`
        }, {
            headers: {
                'Content-Type': 'application/json',
                'Authorization': 'Bearer 4d0f394ec46be1c61d203a4df09da3277aa8c520d922533bf332c7db2c261f61'
            }
        });

        await axios.post('https://bend.logiclane.tech/api/email', {
            subject: 'Short Shift',
            email: 'sandipanchatterjee@live.co.uk',
            name: "Sandy",
            mail: `<!DOCTYPE html>
            <html lang='en' dir='ltr' xmlns:v='urn:schemas-microsoft-com:vml'>
            
            <head>
              <meta charset='utf-8'>
              <meta name='x-apple-disable-message-reformatting'>
              <meta name='viewport' content='width=device-width, initial-scale=1'>
              <meta name='format-detection' content='telephone=no, date=no, address=no, email=no, url=no'>
              <title>Short Shift</title>
              <style>
                .hover-bg-brand-600:hover {
                  background-color: #0047C3 !important;
                }
            
                .hover-text-brand-700:hover {
                  color: #003CA5 !important;
                }
            
                .hover-text-decoration-underline:hover {
                  text-decoration: underline !important;
                }
            
                @media (max-width: 640px) {
                  .sm-mt-4 {
                    margin-top: 16px !important;
                  }
            
                  .sm-block {
                    display: block !important;
                  }
            
                  .sm-w-full {
                    width: 100% !important;
                  }
            
                  .sm-px-4 {
                    padding-left: 16px !important;
                    padding-right: 16px !important;
                  }
            
                  .sm-py-6 {
                    padding-top: 24px !important;
                    padding-bottom: 24px !important;
                  }
                }
            
                table.data-table {
                  width: 100%;
                  border-collapse: collapse;
                  margin-bottom: 24px;
                }
            
                table.data-table th,
                table.data-table td {
                  border: 1px solid #ddd;
                  padding: 8px;
                  text-align: left;
                }
            
                table.data-table th {
                  background-color: #f2f2f2;
                  color: #333;
                }
            
                table.data-table td a {
                  text-decoration: none;
                  color: #fff;
                  background-color: dodgerblue;
                  padding: 10px;
                  border-radius: 4px;
                  display: inline-block;
                }
              </style>
            </head>
            
            <body style='margin: 0; width: 100%; background-color: #fff; padding: 0; -webkit-font-smoothing: antialiased; word-break: break-word'>
              <div style='display: none'>Short Shift</div>
              <div role='article' aria-roledescription='email' aria-label='Please confirm your email address' lang='en'>
                <table style='width: 100%; font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif' cellpadding='0' cellspacing='0' role='none'>
                  <tr>
                    <td align='center' style='background-color: #fff;'>
                      <table class='sm-w-full' style='width: 1366px; ' cellpadding='0' cellspacing='0' role='none'>
                        <tr>
                          <td class='sm-px-4 sm-py-6' style='background-color: #fff; padding: 48px 40px; text-align: center'>
                            <div style='margin-bottom: 24px'>
                              <a href='https://wallet.sweepstake.mobi' style='text-decoration: none; color: #0047C3'>
                                <p>SweepStake Mobi</p>
                              </a>
                            </div>
                            <p style='margin: 0; font-size: 21px; line-height: 28px; color: #4A5566'>Hi Sandy,</p>
                            <table class='data-table' style='width: 640px; margin: 0 auto' cellpadding='0' cellspacing='0' role='none'>
                              <tr>
                                <th style='text-align:left !important;font-size:16px'>Detail</th>
                                <th style='font-size:16px'>Information</th>
                              </tr>
                              <tr>
                                <td style='text-align:left !important; font-size:14px'>Current Cashier</td>
                                <td style='font-size:14px;padding:5px;'>${admin.username}</td>
                              </tr>
                              <tr>
                                <td style='text-align:left !important; font-size:14px'>Last Cashier</td>
                                <td style='font-size:14px;padding:5px;'>${lastAdmin.username}</td>
                              </tr>
                              <tr>
                                <td style='text-align:left !important; font-size:14px'>Short Amount ($)</td>
                                <td style='font-size:14px;padding:5px;'>$ ${amount}</td>
                              </tr>
                            </table>
                            <div role='separator' style='line-height: 16px'>&zwj;</div>
                            <div style='text-align: center;'>
                              <div role='separator' style='background-color: #E1E1EA; height: 1px; line-height: 1px; margin: 64px 0 16px'>&zwj;</div>
                              <p style='margin: 0 0 16px; font-size: 12px; line-height: 16px; color: #8492A6'>
                                This email was sent to you as a registered member of
                                <a href='https://sweepstake.mobi' class='hover-text-brand-700 hover-text-decoration-underline'
                                  style='text-decoration: none; color: #0047C3; display: inline-block;'>SweepStake Mobi</a>. <span
                                  class='sm-block sm-mt-4'>
                                  Use of the service and website is subject to our
                                  <a href='https://sweepstake.mobi/tnc.php' class='hover-text-brand-700 hover-text-decoration-underline'
                                    style='text-decoration: none; color: #0047C3; display: inline-block;'>Terms of Use</a>
                                  and
                                  <a href='https://sweepstake.mobi/privacy-policy.php' class='hover-text-brand-700 hover-text-decoration-underline'
                                    style='text-decoration: none; color: #0047C3; display: inline-block;'>Privacy Statement</a>.
                                </span>
                              </p>
                              <p style='margin: 0; font-size: 12px; line-height: 16px; color: #8492A6;'>&copy; 2024 SweepStake Mobi. All rights reserved.</p>
                            </div>
                          </td>
                        </tr>
                      </table>
                    </td>
                  </tr>
                </table>
              </div>
            </body>
            
            </html>`
        }, {
            headers: {
                'Authorization': `Bearer asda465787xzxc35`,
                'Content-Type': 'application/json'
            }
        })

        return res.status(200).json({ status: 'success', message: 'Short shift saved and sms sent.' });
    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
};

exports.endOtp = async (req, res) => {
    try {
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        const data = {
            userid: admin.id,
            username: admin.username,
            otp_allow: admin.otp_allow,
            message: 'Choose whom to send OTP'
        }
        res.status(200).json({ status: 'success', otpSelect: data });

    } catch (error) {
        if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(error);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}

const numbers = {
    'ray': '19158457387',
    'jacqueline': '19157450006',
    'sandy': '918617368299'
}
const capitalizeFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1);
exports.sendEndOtp = async (req, res) => {
    const { selected } = req.body;
    try {
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        if (!selected) {
            return res.json({ status: 'error', message: 'Selected Admin missing' })
        }

        if (admin.ban != '0') {
            return res.json({ status: 'error', message: `Your account is banned! ${admin.reason}` })
        }

        let phone;
        const selectedKey = selected.toLowerCase();
        if (numbers.hasOwnProperty(selectedKey)) {
            phone = numbers[selectedKey];
        } else {
            return res.json({ status: 'error', message: 'Invalid selected admin' });
        }

        const otp = Math.floor(100000 + Math.random() * 900000).toString();
        // const otp_token = makeid(32);
        // You can send the OTP to the phone number here using your preferred service
        console.log(`Sending OTP ${otp} to phone ${phone}`);
        await sendSMS(phone, otp);
        admin.otp = otp;
        // admin.otp_token = otp_token;
        admin.retry_count = 0;
        await admin.save();

        const data = {
            userid: admin.id,
            username: admin.username,
            otp_allow: admin.otp_allow,
            // otp_token: otp_token,
            selected: capitalizeFirst(selectedKey),
            message: `OTP has been sent to ${capitalizeFirst(selectedKey)}'s phone no`

        }
        return res.json({ status: 'success', otpSent: data });

        // const otp = Math.floor(100000 + Math.random() * 900000).toString();

    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}
exports.resendEndOtp = async (req, res) => {
    const { selected } = req.body;
    try {
        if (!selected) {
            return res.json({ status: 'error', message: ' Selected Admin missing' })
        }
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        const otp = admin.otp;
        // const otp_token = admin.otp_token;
        let phone;
        const selectedKey = selected.toLowerCase();
        if (numbers.hasOwnProperty(selectedKey)) {
            phone = numbers[selectedKey];
        } else {
            return res.json({ status: 'error', message: 'Invalid selected admin' });
        }
        await sendSMS(phone, otp);
        const data = {
            userid: admin.id,
            username: admin.username,
            otp_allow: admin.otp_allow,
            // otp_token: admin.otp_token,
            selected: capitalizeFirst(selectedKey),
            message: `OTP has been re-sent to ${capitalizeFirst(selectedKey)}'s phone no`

        }
        return res.json({ status: 'success', otpSent: data });

    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}
exports.verifyEndOtp = async (req, res) => {
    const { otp } = req.body;
    if (!otp) {
        return res.status(200).json({ status: 'error', message: 'OTP is missing' });
    }
    try {

        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        if (otp == admin.otp) {
            admin.otp = '';
            await admin.save();
            return res.status(200).json({ status: 'success', message: 'OTP Verified' });

        } else {
            return res.status(200).json({ status: 'error', message: 'Incorrect OTP' });
        }
    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}
exports.saveEndShift = async (req, res) => {
    try {
        // console.log(req.body)
        console.log(req.files);
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        const { gdtp, gdtr, gdfb, fstp, fstr, fsfb, rstp, rstr, rsfb } = req.body;

        const files = req.files || {};
        const uploadDir = path.join(__dirname, '../public/evidence/');
        if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true });

        // const saveImage = async (file) => {
        //     const avifName = `${uuidv4()}.avif`;
        //     const outputPath = path.join(uploadDir, avifName);
        //     await sharp(file.buffer).avif({ quality: 50 }).toFile(outputPath);
        //     return avifName;
        // };

        // const gdImg = files[0] ? await saveImage(files[0]) : '';
        // const fsImg = files[1] ? await saveImage(files[1]) : '';
        // const rsImg = files[2] ? await saveImage(files[2]) : '';
        const saveRawImage = async (file) => {
            const rawFileName = `${uuidv4()}${path.extname(file.originalname).toLowerCase()}`;
            const rawFilePath = path.join(uploadDir, rawFileName);

            // Save the raw image to disk
            fs.writeFileSync(rawFilePath, file.buffer);
            return rawFileName;
        };

        // Save the raw images
        const gdImg = files[0] ? await saveRawImage(files[0]) : '';
        const fsImg = files[1] ? await saveRawImage(files[1]) : '';
        const rsImg = files[2] ? await saveRawImage(files[2]) : '';


        console.log(gdImg, fsImg, rsImg)
        const miscLog = await MiscLog.findOne();
        if (!miscLog) return res.status(404).json({ status: 'error', message: 'Misc log not found' });

        // Get fills in last 8 hours
        const eightHoursAgo = moment().subtract(8, 'hours').toDate();

        const [fills, withs] = await Promise.all([
            MiscTxn.findAll({
                where: {
                    admin_id: admin.id,
                    fill_only: '1',
                    created_at: { [Op.gte]: eightHoursAgo }
                },
                order: [['id', 'ASC']]
            }),
            MiscTxn.findAll({
                where: {

                    admin_id: admin.id,
                    with_only: '1',
                    withdraw_reason: { [Op.ne]: '' },
                    withdraw_document: { [Op.ne]: '' },
                    created_at: { [Op.gte]: eightHoursAgo }
                },
                order: [['id', 'ASC']]
            })
        ]);

        // === Fill Amounts
        const fillData = fills.map(f => ({
            init_val: parseFloat(f.initial_balance) || 0,
            new_val: parseFloat(f.new_balance) || 0,
            prev_val: parseFloat(f.prev_balance) || 0,
            fill_val: parseFloat(f.fill_balance) || 0
        }));

        const fillamount = fillData.reduce((acc, curr) =>
            parseFloat(acc) + parseFloat(curr.fill_val), 0
        );

        const fill_prev_bal = parseFloat(fillData.at(-1)?.prev_val) || 0;

        // === Withdrawals
        const withdrawDetails = withs.sort((a, b) => a.id - b.id).map(w => ({
            id: w.id,
            amount: parseFloat(w.withdraw_balance) || 0,
            reason: w.withdraw_reason,
            manager: w.withdraw_manager,
            image: `${process.env.APP_URL}/public/evidence/${w.withdraw_document}`,
            init_val: parseFloat(w.initial_balance) || 0,
            new_val: parseFloat(w.new_balance) || 0
        }));

        const withdrawTotal = withdrawDetails.reduce((sum, w) =>
            parseFloat(sum) + parseFloat(w.amount), 0
        );
        const withDetails = withdrawDetails.sort((a, b) => a.id - b.id)
        // === Final balance calculation
        const parsedGdfb = parseFloat(gdfb) || 0;
        const parsedFsfb = parseFloat(fsfb) || 0;
        const parsedRsfb = parseFloat(rsfb) || 0;

        const lastAdd = parsedGdfb + parsedFsfb + parsedRsfb;


        console.log("withdrawDetails", withdrawDetails)
        console.log("withdrawDetails[0]", withdrawDetails[0])
        console.log("withDetails", withDetails)
        console.log("withDetails[0]", withDetails[0])
        console.log("withDetails[0] Init Val", withDetails[0]?.init_val)

        console.log("withdrawTotal", withdrawTotal)

        // const init_bal = withdrawTotal > 0
        //     ? (parseFloat(withDetails[0]?.init_val) || fill_prev_bal || 0)
        //     : (fill_prev_bal || parseFloat(miscLog.initial_amount) || 0);


        const firstFill = fills[0];
        const firstWithdraw = withs[0];

        let init_bal = 0;

        if (firstFill && firstWithdraw) {
            console.log("firstFill && firstWithdraw")
            // Both exist: compare ids (lower id = earlier)
            if (firstFill.id < firstWithdraw.id) {
                console.log("firstFill.id < firstWithdraw.id")

                init_bal = parseFloat(firstFill.initial_balance) || 0;
            } else {
                console.log("firstFill.id < firstWithdraw.id else")

                init_bal = parseFloat(firstWithdraw.initial_balance) || 0;
            }
        } else if (firstFill) {
            console.log("firstFill")

            // Only fill exists
            init_bal = parseFloat(firstFill.initial_balance) || 0;
        } else if (firstWithdraw) {
            console.log("firstWithdraw")

            // Only withdraw exists
            init_bal = parseFloat(firstWithdraw.initial_balance) || 0;
        } else {
            // Neither exists
            console.log("else")

            init_bal = parseFloat(miscLog.initial_amount) || 0;
        }

        const finalBalance = withdrawTotal > 0
            ? parseFloat(init_bal) + parseFloat(lastAdd) - parseFloat(withdrawTotal) + parseFloat(fillamount)
            : parseFloat(init_bal) + parseFloat(lastAdd) + parseFloat(fillamount);


        console.log(
            [
                "total add", lastAdd,
                "total fill", fillamount,
                "total withdraw", withdrawTotal,
                "initial balance", init_bal,
                "final balance", finalBalance
            ]
        )

        // === Update miscLog
        await miscLog.update({ initial_amount: finalBalance });

        // === Create new misc transaction
        await MiscTxn.create({
            admin_id: admin.id,
            gdtp,
            gdtr,
            gdfb: parsedGdfb,
            gdimage: gdImg,
            fstp,
            fstr,
            fsfb: parsedFsfb,
            fsimage: fsImg,
            rstp,
            rstr,
            rsfb: parsedRsfb,
            rsimage: rsImg,
            prev_balance: parseFloat(miscLog.initial_amount) || 0,
            new_balance: finalBalance,
            initial_balance: parseFloat(miscLog.initial_amount) || 0
        });

        // === Compose email HTML
        const with_img_tr = withDetails.map((w, i) => `
          <tr>
            <td style="text-align:left;font-size:14px">Withdraw${withDetails.length > 1 ? ` ${i + 1}` : ''} Evidence</td>
            <td style="font-size:14px;padding:5px;"><a href="${w.image}" style="border:none;border-radius:5px;padding:5px;color:#fff;background:dodgerblue;text-decoration:none;">Download</a></td>
          </tr>`).join('');

        const with_data_tr = await Promise.all(withDetails.map(async (w, i) => {
            let managerDebtRow = '';
            if (w.manager) {
                const managerOwed = await ManagerOwed.findOne({ where: { manager_username: w.manager } });
                if (managerOwed) {
                    managerDebtRow = `<tr><td style="text-align:left;font-size:14px">Total Debt</td><td style="font-size:14px;padding:5px;">${w.manager} $${managerOwed.amount}</td></tr>`;
                }
            }
            return `
            <tr><td style="text-align:left;font-size:14px">Withdraw${withdrawDetails.length > 1 ? ` ${i + 1}` : ''} Amount</td><td style="font-size:14px;padding:5px;">$${w.amount}</td></tr>
            <tr><td style="text-align:left;font-size:14px">Withdraw Reason</td><td style="font-size:14px;padding:5px;">${w.reason}</td></tr>
            ${w.manager ? `<tr><td style="text-align:left;font-size:14px">Withdraw Manager</td><td style="font-size:14px;padding:5px;">${w.manager}</td></tr>` : ''}
            ${managerDebtRow}
          `;
        }));

        const mailHTML = (toSend) => `
         <!DOCTYPE html>
<html lang='en' dir='ltr' xmlns:v='urn:schemas-microsoft-com:vml'>
<head>
  <meta charset='utf-8'>
  <meta name='x-apple-disable-message-reformatting'>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
  <meta name='format-detection' content='telephone=no, date=no, address=no, email=no, url=no'>
  <title>Shift End Report</title>
  <style>
    .hover-bg-brand-600:hover {
      background-color: #0047C3 !important;
    }

    .hover-text-brand-700:hover {
      color: #003CA5 !important;
    }

    .hover-text-decoration-underline:hover {
      text-decoration: underline !important;
    }

    @media (max-width: 640px) {
      .sm-mt-4 {
        margin-top: 16px !important;
      }

      .sm-block {
        display: block !important;
      }

      .sm-w-full {
        width: 100% !important;
      }

      .sm-px-4 {
        padding-left: 16px !important;
        padding-right: 16px !important;
      }

      .sm-py-6 {
        padding-top: 24px !important;
        padding-bottom: 24px !important;
      }
    }

    table.data-table {
      width: 100%;
      border-collapse: collapse;
      margin-bottom: 24px;
    }

    table.data-table th,
    table.data-table td {
      border: 1px solid #ddd;
      padding: 8px;
      text-align: left;
    }

    table.data-table th {
      background-color: #f2f2f2;
      color: #333;
    }

    table.data-table td a {
      text-decoration: none;
      color: #fff;
      background-color: dodgerblue;
      padding: 10px;
      border-radius: 4px;
      display: inline-block;
    }
  </style>
</head>

<body style='margin: 0; width: 100%; background-color: #fff; padding: 0; -webkit-font-smoothing: antialiased; word-break: break-word'>
  <div style='display: none'>Shift End Report</div>
  <div role='article' aria-roledescription='email' aria-label='Please confirm your email address' lang='en'>
    <table style='width: 100%; font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif' cellpadding='0' cellspacing='0' role='none'>
      <tr>
        <td align='center' style='background-color: #fff;'>
          <table class='sm-w-full' style='width: 1366px; ' cellpadding='0' cellspacing='0' role='none'>
            <tr>
              <td class='sm-px-4 sm-py-6' style='background-color: #fff; padding: 48px 40px; text-align: center'>
                <div style='margin-bottom: 24px'>
                  <a href='https://wallet.sweepstake.mobi' style='text-decoration: none; color: #0047C3'>
                    <p>SweepStake Mobi</p>
                  </a>
                </div>
                <p style='margin: 0; font-size: 21px; line-height: 28px; color: #4A5566'>Hi ${toSend},</p>
                <table class='data-table' style='width: 640px; margin: 0 auto' cellpadding='0' cellspacing='0' role='none'>
                  <tr>
                    <th style='text-align:left !important;font-size:16px'>Detail</th>
                    <th style='font-size:16px'>Information</th>
                  </tr>
                  <tr>
                    <td style='text-align:left !important; font-size:14px'>Admin</td>
                    <td style='font-size:14px;padding:5px;'>${admin.username}</td>
                  </tr>
                  <tr>
                    <td style='text-align:left !important; font-size:14px'>Initial Balance</td>
                    <td style='font-size:14px;padding:5px;'>$${init_bal}</td>
                  </tr>
                  
                  <tr>
                                    <td style='text-align:left !important; font-size:14px'>Golden Dragon Purchases</td>
                                    <td style='font-size:14px;padding:5px;'>$${gdtp}</td>
                                  </tr>
                                  <tr>
                                    <td style='text-align:left !important; font-size:14px'>Golden Dragon Redeems</td>
                                    <td style='font-size:14px;padding:5px;'>$${gdtr}</td>
                                  </tr>
                                  <tr>
                                    <td style='text-align:left !important; font-size:14px'>Golden Dragon Final Balance</td>
                                    <td style='font-size:14px;padding:5px;'>$${gdfb}</td>
                                  </tr>
                                  <tr>
                                    <td style='text-align:left !important; font-size:14px'>Fire Storm Purchases</td>
                                    <td style='font-size:14px;padding:5px;'>$${fstp}</td>
                                  </tr>
                                  <tr>
                                    <td style='text-align:left !important; font-size:14px'>Fire Storm Redeems</td>
                                    <td style='font-size:14px;padding:5px;'>$${fstr}</td>
                                  </tr>
                                  <tr>
                                    <td style='text-align:left !important; font-size:14px'>Fire Storm Final Balance</td>
                                    <td style='font-size:14px;padding:5px;'>$${fsfb}</td>
                                  </tr>
                                  <tr>
                                    <td style='text-align:left !important; font-size:14px'>River Sweeps Purchases</td>
                                    <td style='font-size:14px;padding:5px;'>$${rstp}</td>
                                  </tr>
                                  <tr>
                                    <td style='text-align:left !important; font-size:14px'>River Sweeps Redeems</td>
                                    <td style='font-size:14px;padding:5px;'>$${rstr}</td>
                                  </tr>
                                  <tr>
                                    <td style='text-align:left !important; font-size:14px'>River Sweeps Final Balance</td>
                                    <td style='font-size:14px;padding:5px;'>$${rsfb}</td>
                                  </tr>
                                   <tr>
                                  <td style='text-align:left !important; font-size:14px'>Fill Amount</td>
                                  <td style='font-size:14px;padding:5px;'>$${fillamount}</td>
                                </tr>
                  <tr>
                    <td style='text-align:left !important; font-size:14px'>Final Balance</td>
                    <td style='font-size:14px;padding:5px;'>$${finalBalance}</td>
                  </tr>
                  ${with_data_tr.join('')}

                  <tr >
                                    <td style='text-align:left !important; font-size:14px'>Golden Dragon Evidence</td>
                                    <td style='font-size:14px;padding:5px;'><a href='${process.env.APP_URL}/public/evidence/${gdImg}' style='border:none;border-radius:5px;padding:5px;color:#fff;background:dodgerblue;text-decoration:none;'>Download</a></td>
                                  </tr>
                                  <tr >
                                    <td style='text-align:left !important; font-size:14px'>Fire Storm Evidence</td>
                                    <td style='font-size:14px;padding:5px;'><a href='${process.env.APP_URL}/public/evidence/${fsImg}' style='border:none;border-radius:5px;padding:5px;color:#fff;background:dodgerblue;text-decoration:none;'>Download</a></td>
                                  </tr>
                                  <tr >
                                    <td style='text-align:left !important; font-size:14px'>River Sweeps Evidence</td>
                                    <td style='font-size:14px;padding:5px;'> <a href='${process.env.APP_URL}/public/evidence/${rsImg}' style='border:none;border-radius:5px;padding:5px;color:#fff;background:dodgerblue;text-decoration:none;'>Download</a></td>
                                  </tr>
                  ${with_img_tr}
                </table>
                <div role='separator' style='line-height: 16px'>&zwj;</div>
                <div style='text-align: center;'>
                  <div role='separator' style='background-color: #E1E1EA; height: 1px; line-height: 1px; margin: 64px 0 16px'>&zwj;</div>
                  <p style='margin: 0 0 16px; font-size: 12px; line-height: 16px; color: #8492A6'>
                    This email was sent to you as a registered member of
                    <a href='https://sweepstake.mobi' class='hover-text-brand-700 hover-text-decoration-underline'
                      style='text-decoration: none; color: #0047C3; display: inline-block;'>SweepStake Mobi</a>. <span
                      class='sm-block sm-mt-4'>
                      Use of the service and website is subject to our
                      <a href='https://sweepstake.mobi/tnc.php' class='hover-text-brand-700 hover-text-decoration-underline'
                        style='text-decoration: none; color: #0047C3; display: inline-block;'>Terms of Use</a>
                      and
                      <a href='https://sweepstake.mobi/privacy-policy.php' class='hover-text-brand-700 hover-text-decoration-underline'
                        style='text-decoration: none; color: #0047C3; display: inline-block;'>Privacy Statement</a>.
                    </span>
                  </p>
                  <p style='margin: 0; font-size: 12px; line-height: 16px; color: #8492A6;'>&copy; 2024 SweepStake Mobi. All rights reserved.</p>
                </div>
              </td>
            </tr>
          </table>
        </td>
      </tr>
    </table>
  </div>
</body>

</html>
        `;

        const emailRecipients = [
            { email: 'aidenmctavish@gmail.com', name: 'Aiden' },
            // { email: 'mctavishaiden@gmail.com', name: 'McTavish' },
            { email: 'sandipanchatterjee@live.co.uk', name: 'Sandy' },
            { email: 'adrianjacquiemaese@gmail.com', name: 'Jacki' },
            { email: 'ray@rcamusementllc.com', name: 'Ray' }
        ];

        await Promise.all(emailRecipients.map((recipient) =>
            axios.post('https://bend.logiclane.tech/api/email', {
                subject: 'Shift End Report',
                email: recipient.email,
                name: recipient.name,
                mail: mailHTML(recipient.name)
            }, {
                headers: {
                    'Authorization': `Bearer asda465787xzxc35`,
                    'Content-Type': 'application/json'
                }
            })
        ));

        res.json({ status: 'success', message: 'Shift ended and report sent' });

        const convertToAVIF = async (fileName) => {
            const rawFilePath = path.join(uploadDir, fileName);
            const avifName = `${uuidv4()}.avif`;
            const avifPath = path.join(uploadDir, avifName);

            try {
                await sharp(rawFilePath)
                    .avif({ quality: 50 })
                    .toFile(avifPath);
                console.log(`AVIF version saved: ${avifPath}`);

                // Delete the original raw file after conversion
                // fs.unlink(rawFilePath, (err) => {
                //     if (err) {
                //         console.warn(`Error deleting raw file ${rawFilePath}:`, err.message);
                //     } else {
                //         console.log(`Raw file deleted: ${rawFilePath}`);
                //     }
                // });
            } catch (err) {
                console.warn(`AVIF conversion failed for ${rawFilePath}:`, err.message);
            }
        };

        // Convert images to AVIF in the background
        if (gdImg) convertToAVIF(gdImg);
        if (fsImg) convertToAVIF(fsImg);
        if (rsImg) convertToAVIF(rsImg);

    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}

exports.transactions = async (req, res) => {
    try {

        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        const txns = await MiscTxn.findAndCountAll({
            order: [['id', 'desc']],
            include: {
                model: Admin,
                required: true
            }
        })
        const rows = txns.rows.map(txn => {
            const json = txn.toJSON();
            const createdAt = txn.get('created_at');

            return {
                ...json,
                created_at: createdAt instanceof Date ? createdAt.toISOString() : new Date(createdAt).toISOString()
            };
        });
        return res.json({
            status: 'success',
            data: {
                count: txns.count,
                rows
            }
        });
    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}
exports.managerWithdrawals = async (req, res) => {
    try {

        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        const txns = await MiscTxn.findAndCountAll({
            where: {
                withdraw_manager: { [Op.ne]: '' },
                with_only: '1'
            },
            order: [['id', 'desc']],

        })
        const rows = txns.rows.map(txn => {
            const json = txn.toJSON();
            const createdAt = txn.get('created_at');

            return {
                ...json,
                created_at: createdAt instanceof Date ? createdAt.toISOString() : new Date(createdAt).toISOString()
            };
        });
        return res.json({
            status: 'success',
            data: {
                count: txns.count,
                rows
            }
        });
    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}
exports.clearManagerWithdrawals = async (req, res) => {
    try {

        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        const txns = await ManagerOwed.findAndCountAll({
            order: [['id', 'desc']],
            include: {
                model: Admin,
                required: true
            }
        })
        const rows = txns.rows.map(txn => {
            const json = txn.toJSON();
            const createdAt = txn.get('created_at');

            return {
                ...json,
                created_at: createdAt instanceof Date ? createdAt.toISOString() : new Date(createdAt).toISOString()
            };
        });
        return res.json({
            status: 'success',
            data: {
                count: txns.count,
                rows
            }
        });
    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}
exports.clearDebt = async (req, res) => {
    try {
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(401).json({ error: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(401).json({ error: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(404).json({ error: 'Admin not found' });
        }
        if (admin.role != 'Super') {
            return res.status(401).json({ error: 'Unauthorized' });
        }
        const { admin_id } = req.body;

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

        const cashier = await Admin.findOne({ where: { id: admin_id } });
        if (!cashier) {
            return res.status(404).json({ error: 'Admin Not Found!' });
        }

        const manager_owed = await ManagerOwed.findOne({ where: { manager_id: admin_id } })
        manager_owed.amount = 0;
        await manager_owed.save();

        return res.status(200).json({ message: 'Manager Debt Cleared' });

    } catch (error) {
        if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
            return res.status(401).json({ error: 'Token is invalid or has expired' });
        }

        console.error(error);
        res.status(500).json({ error: 'Internal server error' });
    }
}
exports.shortShift = async (req, res) => {
    try {

        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;

        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(200).json({ error: 'Admin not found' });
        }
        const txns = await ShortShift.findAndCountAll({
            order: [['id', 'desc']],
            include: [
                { model: Admin, as: 'currentAdmin', required: true },
                { model: Admin, as: 'lastAdmin', required: true }
            ]
        })
        const rows = txns.rows.map(txn => {
            const json = txn.toJSON();
            const createdAt = txn.get('created_at');

            return {
                ...json,
                created_at: createdAt instanceof Date ? createdAt.toISOString() : new Date(createdAt).toISOString()
            };
        });
        return res.json({
            status: 'success',
            data: {
                count: txns.count,
                rows
            }
        });
    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(200).json({ status: 'error', message: 'Internal server error' });
    }
}

exports.rcllcClicks = async (req, res) => {
    const pool = mysql.createPool({
        host: process.env.EXT_DB_HOST,
        port: process.env.EXT_DB_PORT,
        user: process.env.EXT_DB_USERNAME,
        password: process.env.EXT_DB_PASSWORD,
        database: process.env.EXT_DB_DATABASE,
        waitForConnections: true,
        connectionLimit: 5,
        queueLimit: 0
    });

    let conn;

    try {
        const authHeader = req.headers['authorization'] || req.headers['Authorization'];
        if (!authHeader) {
            return res.status(200).json({ status: 'error', message: 'Authorization header is missing' });
        }

        const token = authHeader.split(' ')[1];
        if (!token) {
            return res.status(200).json({ status: 'error', message: 'Token is missing' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const adminId = decoded.id;
        const admin = await Admin.findOne({ where: { id: adminId } });
        if (!admin) {
            return res.status(404).json({ error: 'Admin not found' });
        }
        if (admin.role != 'Super') {
            return res.status(401).json({ error: 'Unauthorized' });
        }
        // Optional: Validate admin existence if needed

        const page = parseInt(req.query.page) || 1;
        const limit = 10;
        const offset = (page - 1) * limit;

        conn = await pool.getConnection();

        const [rows] = await conn.query(
            'SELECT * FROM clicklog ORDER BY id DESC LIMIT ? OFFSET ?',
            [limit, offset]
        );

        const [[{ count }]] = await conn.query('SELECT COUNT(*) as count FROM clicklog');

        return res.json({
            status: 'success',
            data: {
                count,
                rows
            }
        });
    } catch (err) {
        if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
            return res.status(200).json({ status: 'error', message: 'Token is invalid or has expired' });
        }

        console.error(err);
        res.status(500).json({ status: 'error', message: 'Internal server error' });
    } finally {
        if (conn) conn.release();
        await pool.end(); // Properly closes the pool
    }
};