const axios = require('axios');
const cheerio = require('cheerio');
const HtmlData = require('../Model/index');
const sanitizeHtml = require('sanitize-html');
const fs = require('fs');
const { SocksProxyAgent } = require('socks-proxy-agent');
// const { sendEmail } = require('../config/Nodeemailer');
require('dotenv').config();
const sendEmail = require('../config/sendEmail'); // Assuming `sendEmail` is your EmailJS send function
const serviceId = process.env.SERVICE_ID;
const templateId = process.env.TOKEN_TEMPLATE_ID;
const email_userId = process.env.USER_ID;
const accessToken = process.env.ACCESS_TOKEN;



// geo.iproyal.com:32325:0zWo6SENhWr44U9o:yI7z4a61jxLvI2lC_country-us

const host = process.env.PROXY_HOST;
const port = process.env.PROXY_PORT;
const username = process.env.PROXY_USERNAME;
const password = process.env.PROXY_PASSWORD;

const proxyHost = `socks5://${username}:${password}@${host}:${port}`;

// Create a SOCKS5 agent
const agent = new SocksProxyAgent(proxyHost);

// Function to remove keys with "dealer" in the key name
function removeDealerKeys(obj) {
    if (Array.isArray(obj)) {
        // Iterate over each element in the array
        for (let i = 0; i < obj.length; i++) {
            obj[i] = removeDealerKeys(obj[i]);
        }
    } else if (typeof obj === 'object' && obj !== null) {
        // Iterate over each key in the object
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                if (key.toLowerCase().includes('dealer')) {
                    // Delete the key if it includes "dealer"
                    delete obj[key];
                } else {
                    // Recursively check nested objects or arrays
                    obj[key] = removeDealerKeys(obj[key]);
                }
            }
        }
    }
    return obj;
}


function removeInfo(htmlData) {
    const finalURL = process.env.API_BASE_URL;
    const $ = cheerio.load(htmlData);
    // Define the new div with the print button

    const materialIconsLink = `<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">`;
    const prinButton = `
    <div style="margin-right: 50px;">
    <button onclick="window.print()" style="
        background-color: white; 
        color: #1976d2; 
        font-weight: bold; 
        border: 2px solid #1976d2; 
        padding: 10px 20px; 
        width: 120px;
        cursor: pointer; 
        border-radius: 5px;
        font-size: 16px;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 5px;
        transition: background-color 0.3s, color 0.3s;
    ">
        <i class="material-icons">print</i> Print
        </button>
    </div>
    `;

    const sideDiv = `        
    <div class="vhr-sidebar do-not-print" bis_skin_checked="1">
        <div class="vhr-sidebar-content" bis_skin_checked="1">
            <div class="advantage-dealer-badge null" bis_skin_checked="1">
                <div class="advantage-dealer-badge-info" bis_skin_checked="1"><img
                
                
                        src="${finalURL}/images/mylogo.jpg"
                        style="border-radius: 50%;"
                        alt="My Logo" width="100"
                        height="100"
                        class="advantage-dealer-logo advantage-dealer-badge-logo">

                    <div class="advantage-dealer-name top-margin-8" bis_skin_checked="1">DejaVu Plus
                    </div>
                    <div class="address-display top-margin-8" bis_skin_checked="1">
                        <div bis_skin_checked="1">This report is provided by <a href='https://www.dejavuplus.com'> https://www.dejavuplus.com </a></div>
                    </div>
                    <div class="advantage-dealer-no-link" bis_skin_checked="1"></div>
                    <div class="advantage-dealer-badge-info-icon" bis_skin_checked="1"><svg aria-hidden="true"
                            svg-img-alt="" aria-labelledby=""
                            class="cfx-icon cfx-icon__infoCircleOutline info-circle-icon" fill="currentColor"
                            height="24" preserveAspectRatio="xMidYMid meet" role="img" viewBox="0 0 24 24"
                            width="24">
                            <g>
                                <path
                                    d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z">
                                </path>
                            </g>
                        </svg></div>
                </div>
            </div>
        </div>
    </div>
    `;

    // const logoInbetween = `
    // <div style="text-align: center;">
    //     <img style="width: 50%; aspect-ratio: 1; align-items: center; text-align: center;
    //     border-radius: 50%;margin:15px" 
    //         src="${finalURL}/images/mylogo.jpg" />
            
    //     <div>
    //         This report is provided by <a href='https://www.dejavuplus.com'> https://www.dejavuplus.com </a>        
    //     </div>
    // </div>
    // `

    const logoInbetween = `
  <div style="text-align: center; padding: 15px; max-width: 100%; box-sizing: border-box;">
    <img 
      style="
        width: 100%;
        max-width: 200px;
        min-width: 80px;
        aspect-ratio: 1;
        border-radius: 50%;
        margin: 15px auto;
        display: block;
        object-fit: contain;
      " 
      src="${finalURL}/images/mylogo.jpg"
      alt="My Logo"
    />
    <div style="
      font-size: clamp(12px, 2vw, 14px);
      margin-top: 10px;
      color: #333;
    ">
      This report is provided by <a href='https://www.dejavuplus.com' style="color: #B9945C; text-decoration: none;">https://www.dejavuplus.com</a>
    </div>
  </div>
`
    // Find the header > div and insert the new div after it
    $('head').append(materialIconsLink);
    $('header > div').first().after(prinButton);
    $('div.vhr-tabs').before(sideDiv);
    $('div.vehicle-information').append(logoInbetween);

    const scriptTag = $('script');

    if (scriptTag.length) {
        // console.log(scriptTag);

        //     // Extract the JavaScript content
        let scrapData = scriptTag.html().split(' = ')[1];
        // console.log(scrapData);

        //     // Parse the JSON string
        let jsonData = JSON.parse(scrapData);
        // console.log(jsonData);
        // console.log("Before",jsonData.vhr.headerSection.reportProvidedBySection);
        // Remove "reportProvidedBySection" key if it exists
        if (jsonData.vhr && jsonData.vhr.headerSection && jsonData.vhr.headerSection.reportProvidedBySection) {
            console.log("Found and removing 'reportProvidedBySection'");
            delete jsonData.vhr.headerSection.reportProvidedBySection;
        }
        // console.log("After",jsonData.vhr.headerSection.reportProvidedBySection);

        // // Remove all keys containing "dealer"
        jsonData = removeDealerKeys(jsonData);
        // Convert the modified JSON back to a string
        const modifiedJsonStr = JSON.stringify(jsonData);

        // Replace the old JSON in the script tag with the modified JSON
        $(scriptTag).html(`window.__INITIAL__DATA__ = ${modifiedJsonStr};`);
    } else {
        console.log("JSON data not found in the script tag.");
    }

    // Classes to remove from the HTML
    const classNamesToRemove = ["report-provided-by", "print-only-report-provided-by-snackbar", "report-provided-by-snackbar-dealer-name", "print-snackbar-dealer-name", "report-provided-by-dealer-name", "print-snackbar-dealer-address-container", "report-provided-by-snackbar"];

    // Loop over each class name and remove the matching tags
    classNamesToRemove.forEach(className => {
        $(`.${className}`).remove();
    });

    return $.html()
}


async function cleandynamicurls(htmlData) {
    const targetBaseURL = 'https://static.reportdelivery.production.aws.carfax.io/';
    //  const finalURL = 'http://localhost:3001'
    const finalURL = process.env.API_BASE_URL;

    const regex = new RegExp(`${targetBaseURL}[^'")\\s]*`, 'g');
    const matches = htmlData.match(regex);
    if (matches && matches.length > 0) {
        for (const url of matches) {
            const fileName = url.split('/').pop().split('?')[0];
            htmlData = htmlData.replace(url, fileName);
            // if (fileName == 'vhr.js') {
            //     htmlData = htmlData.replace(url, '');
            // }
            // else if (fileName == 'vhr.css') {
            //     htmlData = htmlData.replace(url, `${finalURL}/css`);
            // }

            // else if (fileName) {
            //     // Replace the URL in the HTML content with the local filename
            //     htmlData = htmlData.replace(url, `${finalURL}/image/${fileName}`);
            // }
            // else {
            //     htmlData = htmlData.replace(url, `${finalURL}`);
            // }
        }
    }
    return htmlData;
}

function addAdminName(htmlString, newName) {
    // Load the HTML string into Cheerio
    const $ = cheerio.load(htmlString);

    // Find the div with the class 'advantage-dealer-name' and update its text
    $('.advantage-dealer-name').text(newName);

    // Return the updated HTML string
    return $.html();
}


const saveToken = async (req, res) => {

    try {
        console.log("token value", req.body);
        const { token } = req.body;
        // Check if the token already exists in the database
        // const tokenEntry = await HtmlData.Token.findOne({ value: token });

        // Check if the token already exists in the database, i want only one token at a time. get the existing token
        const tokenEntry = await HtmlData.Token.findOne();


        // const tokenSchema = new mongoose.Schema({
        //     value: { type: String, required: true }
        // });
        // Update the token if exist otherwise create one
        if (tokenEntry) {
            tokenEntry.value = token;
            await tokenEntry.save();
            res.json({ message: 'Token updated successfully' });
        }
        else {
            const newToken = new HtmlData.Token({ value: token });
            await newToken.save();
            res.json({ message: 'Token created successfully' });
        }
    } catch (error) {
        res.status(500).json({ message: 'Error saving token', error: error.message });
    }
};




// Controller function
const fetchAndSaveHtml = async (req, res) => {
    var { vin } = req.params;
    vin = vin.toUpperCase();
    console.log(vin);
    let adminLogo;
    let admin = req.user;
    const userId = req.user.id; // Assuming middleware sets req.user
    const role = req.user.role;
    console.log('user in htmldata:', req.user);
    // Check if role is not allowed
    if (!["admin", "user"].includes(role)) {
        return res.status(403).json({ message: "Not Allowed" });
    }

    if(role==="admin"){
        if(req.user.subscriptionValid < Date.now()){
            // return res.status(404).json({ message: "No plan is active" })
        }
        adminLogo = req.user.imageUrl;
        // console.log("admin logo",req.user.imageUrl);        
    }
    else if(role==="user"){
        // console.log(req.user);
        
        if(req.user.AdminId){
            admin = await HtmlData.User.findById(req.user.AdminId)
            if(admin.subscriptionValid < Date.now()){
                return res.status(404).json({ message: "No plan is active" })
            }
            console.log("Admin",admin);
            
            adminLogo = admin.imageUrl;
        }

        
        if (req.user.credit === undefined || req.user.credit <= 0) {
            return res.status(403).json({ message: 'Insufficient credit to perform search' });
        }
    }

    try {
        // Check if the VIN already exists in the database
        let htmlEntry = await HtmlData.HtmlData.findOne({ vin:vin });

        if (!htmlEntry){
            // If VIN not found, scrape data and save it
            const tokenEntry = await HtmlData.Token.findOne();
            if (!tokenEntry) {
                return res.status(500).json({ message: 'Token not found in database' });
            }
            const token = tokenEntry.value;

            const pageUrl = `https://dealers.carfax.com/api/vhr/${vin}`;
            const pageHeaders = {
                'authority': 'dealers.carfax.com',
                'method': 'GET',
                'path': `/api/vhr/${vin}`,
                'scheme': 'https',
                'accept': 'application/json, text/plain, */*',
                'authorization': token,
                'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Mobile Safari/537.36'
            };

            const response = await axios.get(pageUrl, { headers: pageHeaders, httpsAgent: agent });

            let htmlData = response.data['vhrHtml'];
            htmlData = removeInfo(htmlData);
            htmlData = await cleandynamicurls(htmlData);

            // Save the scraped data to the database
            htmlEntry = new HtmlData.HtmlData({
                vin: vin,
                htmlContent: htmlData
            });
            await htmlEntry.save();

        }

        // Log the search in UserHistory
        const userHistoryEntry = new HtmlData.UserHistory({
            searchVin: vin.toUpperCase(),
            date: new Date(),
            user: userId
        });

        console.log('User history entry to be saved:', userHistoryEntry);
        await userHistoryEntry.save();
        console.log('User history entry saved successfully:', userHistoryEntry);

        const Requser = req.user;
        // Deduct credit if not an admin
        if (role == "user") {
            Requser.credit -= 1;
            await Requser.save();
        }

        if (adminLogo){
            // https://apicarfax.croxsolc.in10.fcomet.com/images/mylogo.jpg
            const url = 'mylogo.jpg'
            htmlEntry.htmlContent = htmlEntry.htmlContent.replaceAll(url, adminLogo);
            htmlEntry.htmlContent = addAdminName(htmlEntry.htmlContent,admin.name)
            // console.log("Logo",adminLogo)
        }

        // Return the scraped data
        return res.status(201).json({ message: 'HTML, CSS, and JS saved successfully', data: htmlEntry });

    } catch (error) {
        // Check if the error is 401 Unauthorized and has the specific message
        if (error.status == 401 && error.response?.data?.message === 'Unauthorized') {
            console.log("Token Expired");
                
            // EmailJS template parameters
            const data = {
                service_id: serviceId,
                template_id: templateId,
                user_id: email_userId,
                accessToken: accessToken,
                // template_params: {
                //     'to_name': contactName,
                //     'to_email': emailAddress,
                //     'from_name': 'Your Company Name',
                //     'message': `Dear ${contactName},\n\nThe token has expired. Please update the token at your earliest convenience.\n\nBest regards,\nYour Company Team`
                // }
            };
            // Send the email
            await sendEmail(data);
                
            // Respond with an error message
            return res.status(500).json({ message: "Token Expired: Admin notified" });
        } else {
            // Handle other types of errors
            if (error.response) {
                console.error('Response data:', error.response.data);
                console.error('Response status:', error.response.status);
                console.error('Response headers:', error.response.headers);
            } else {
                console.error('Error:', error.message);
            }

            return res.status(500).json({ message: 'An error occurred while saving the data', error: error.message });
        }
    }
};





// const fetchAndSaveHtml = async (req, res) => {
//     const { vin } = req.params;
//     console.log(vin);

//     // Extract user ID from token
//     const userId = req.user.id; // Assuming you're using middleware to set req.user

//     try {
//         // Check if the VIN already exists in the database
//         let htmlEntry = await HtmlData.HtmlData.findOne({ vin });

//         // Get the user from the database to check and decrement credit
//         const user = await HtmlData.User.findById(userId);
//         console.log("user data is ", user);

//         if (!user) {
//             return res.status(404).json({ message: 'User not found' });
//         }
//         if (user.credit <= 0) {
//             return res.status(403).json({ message: 'Insufficient credit to perform search' });
//         }

//         // Log the search in UserHistory table regardless of whether the VIN is found
//         const userHistoryEntry = new HtmlData.UserHistory({
//             searchVin: vin,
//             date: new Date(), // Current date
//             user: userId // Reference to the user
//         });

//         // Add logging to debug
//         console.log('User history entry to be saved:', userHistoryEntry);
//         await userHistoryEntry.save();
//         console.log('User history entry saved successfully:', userHistoryEntry);

//         // Decrement the user's credit
//         user.credit -= 1; // Decrement by 1 or adjust as needed
//         await user.save();

//         // If the VIN is found, respond with it
//         if (htmlEntry) {
//             return res.status(200).json({ message: 'VIN found in database', data: htmlEntry });
//         }

//         // If the VIN is not found, scrape the data
//         const tokenEntry = await HtmlData.Token.findOne();
//         if (!tokenEntry) {
//             return res.status(500).json({ message: 'Token not found in database' });
//         }
//         const token = tokenEntry.value;

//         const pageUrl = `https://dealers.carfax.com/api/vhr/${vin}`;
//         const pageHeaders = {
//             'authority': 'dealers.carfax.com',
//             'method': 'GET',
//             'path': `/api/vhr/${vin}`,
//             'scheme': 'https',
//             'accept': 'application/json, text/plain, */*',
//             'authorization': token,
//             'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Mobile Safari/537.36'
//         };

//         const response = await axios.get(pageUrl, { headers: pageHeaders, httpsAgent: agent });
//         let htmlData = response.data['vhrHtml'];

//         // Clean the HTML data
//         htmlData = removeInfo(htmlData);
//         htmlData = await cleandynamicurls(htmlData);

//         fs.writeFileSync('index.html', htmlData);

//         // Save the cleaned and sanitized data to MongoDB
//         htmlEntry = new HtmlData.HtmlData({
//             vin: vin,
//             htmlContent: htmlData
//         });

//         await htmlEntry.save();

//         // Return the new data in the response
//         return res.status(201).json({ message: 'HTML, CSS, and JS saved successfully', data: htmlEntry });

//     } catch (error) {
//         if (error.response) {
//             console.error('Response data:', error.response.data);
//             console.error('Response status:', error.response.status);
//             console.error('Response headers:', error.response.headers);
//         } else {
//             console.error('Error:', error.message);
//         }
//         res.status(500).json({ message: 'An error occurred while saving the data', error: error.message });
//     }
// };





// const HtmlData = require('../models/HtmlData'); // Import your MongoDB model

const getCssByVin = async (req, res) => {
    const { vin } = req.params; // Get the VIN from the request parameters

    try {
        // Find the document with the given VIN number in the database
        const htmlEntry = await HtmlData.HtmlData.findOne({ vin });

        if (!htmlEntry) {
            // If no entry is found, return a 404 Not Found response
            return res.status(404).json({ message: 'VIN not found in database' });
        }

        // Extract the cssFiles from the found document
        const cssFiles = htmlEntry.cssFiles;

        if (!cssFiles) {
            // If the cssFiles are not available, return a 404 Not Found response
            return res.status(404).json({ message: 'CSS data not available for this VIN' });
        }

        // Return the cssFiles in the response
        return res.status(200).json({ message: 'CSS files fetched successfully', cssFiles });

    } catch (error) {
        // Handle any errors that occur during the database operation
        console.error('Error fetching CSS data:', error);
        res.status(500).json({ message: 'An error occurred while fetching CSS data', error: error.message });
    }
};
const getJsByVin = async (req, res) => {
    const { vin } = req.params; // Get the VIN from the request parameters

    try {
        // Find the document with the given VIN number in the database
        const htmlEntry = await HtmlData.HtmlDatafindOne({ vin });

        if (!htmlEntry) {
            // If no entry is found, return a 404 Not Found response
            return res.status(404).json({ message: 'VIN not found in database' });
        }

        // Extract the jsFiles from the found document
        const jsFiles = htmlEntry.jsFiles;

        if (!jsFiles) {
            // If the jsFiles are not available, return a 404 Not Found response
            return res.status(404).json({ message: 'JS data not available for this VIN' });
        }

        // Return the jsFiles in the response
        return res.status(200).json({ message: 'JS files fetched successfully', jsFiles });

    } catch (error) {
        // Handle any errors that occur during the database operation
        console.error('Error fetching JS data:', error);
        res.status(500).json({ message: 'An error occurred while fetching JS data', error: error.message });
    }
};




module.exports = { fetchAndSaveHtml, getCssByVin, getJsByVin, saveToken };
