const db = require("../config/db"); // Assuming you have set up the database connection
const jwt = require("jsonwebtoken");
const bcrypt = require('bcrypt');
const axios = require("axios"); // Import axios for making HTTP requests
const https = require('https');
const fs = require('fs');
const path = require('path');
const CryptoJS = require('crypto-js'); // Import the crypto-js library

// Helper function to write logs to a file
const logToFile1 = (message) => {
  // Format current date as DD-MMM-YYYY
  const currentDate = new Date().toLocaleDateString('en-GB', {
    day: '2-digit',
    month: 'short',
    year: 'numeric'
  }).replace(/ /g, '-'); // e.g., "20-Feb-2025"
  
  // Construct log file name based on the current date
  const logFileName = `server-${currentDate}.log`;
  const logFilePath = path.join(__dirname, 'logs', logFileName); // Dynamic file name based on date

  // Ensure the 'logs' directory exists
  if (!fs.existsSync(path.dirname(logFilePath))) {
    try {
      fs.mkdirSync(path.dirname(logFilePath), { recursive: true });
    } catch (error) {
      console.error("Error creating log directory:", error);
    }
  }

  // Construct the log message with timestamp
  const logMessage = `${new Date().toISOString()} - ${message}\n`;

  // Append log message to the file
  try {
    fs.appendFileSync(logFilePath, logMessage, 'utf8');
  } catch (error) {
    console.error("Error writing to log file:", error);
  }
};

const generateUniqueHashId = () => {
  const timestamp = Date.now(); // Current timestamp (milliseconds)
  return timestamp.toString(36); // timestamp unique per mili sec
};



// Common functions 

// FOR BUNNY - START 


const BUNNY_REGION = 'ny'; // Your Bunny CDN region
const BUNNY_BASE_HOSTNAME = 'storage.bunnycdn.com';
const BUNNY_HOSTNAME = BUNNY_REGION ? `${BUNNY_REGION}.${BUNNY_BASE_HOSTNAME}` : BUNNY_BASE_HOSTNAME;
const BUNNY_STORAGE_ZONE_NAME = 'bigscreensocial'; // Your Bunny Storage Zone Name
const BUNNY_ACCESS_KEY = 'a4d9fb3d-c17a-4a78-bcfb0fe2f1ae-8767-4b0d';
const BUNNY_STREAM_ACCESS_KEY='96e74369-2f81-4a63-9811b265f755-cf10-474d';
const BUNNY_CDN_BASE_URL = 'https://BigScreenSocial.b-cdn.net';
const BUNNY_LIBRARY_ID = '366380';
const BUNNY_STREAM_BASE_URL = 'https://vz-3d811857-5d8.b-cdn.net';

// Function to calculate SHA-256 signature
function bunnyVideoSHA256(str) {
  return CryptoJS.SHA256(str).toString(CryptoJS.enc.Hex);
}

// Function to calculate the signature
function bunnyVideoCalculateSignature(library_id, api_key, expiration_time, video_id) {
  const string_signature = library_id + api_key + expiration_time + video_id;
  return bunnyVideoSHA256(string_signature); // Generate and return the signature
}

// Helper function to upload files to Bunny CDN
const uploadFileToBunny = async (file_name, file_path, file_save_prefix_folder='') => {
  
  logToFile1(`Starting file upload: ${file_name}`); // Log start of the upload

  return new Promise((resolve, reject) => {
    const readStream = fs.createReadStream(file_path);
    
    // Encode the file name to escape special characters
    const encodedFileName = encodeURIComponent(file_name);
    
    let bunny_full_path;
    let bunny_prefix_plus_filename;
    
    if(file_save_prefix_folder)
    {
        bunny_full_path=`/${BUNNY_STORAGE_ZONE_NAME}/${file_save_prefix_folder}/${encodedFileName}`;
        bunny_prefix_plus_filename=`${file_save_prefix_folder}/${encodedFileName}`;
    }
    else
    {
        bunny_full_path=`/${BUNNY_STORAGE_ZONE_NAME}/${encodedFileName}`;
        bunny_prefix_plus_filename=encodedFileName;
    }
    

    const options = {
      method: 'PUT',
      host: BUNNY_HOSTNAME,
      path: bunny_full_path,
      headers: {
        AccessKey: BUNNY_ACCESS_KEY,
        'Content-Type': 'application/octet-stream',
      },
    };

    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk.toString('utf8');
      });

      res.on('end', () => {
        const fileUrl = `${BUNNY_CDN_BASE_URL}/${bunny_prefix_plus_filename}`;
        logToFile1(`File uploaded successfully: ${fileUrl}`); // Log successful upload
        resolve(fileUrl); // Return the file URL
      });
    });

    req.on('error', (error) => {
      logToFile1(`Error uploading file: ${error.message}`); // Log error
      reject(error);
    });

    readStream.pipe(req);
    logToFile1(`File upload initiated for: ${file_name}`); // Log file upload initiation
  });
};


const deleteFileFromBunny = async (fileName) => {
    try {
        logToFile1(`Starting file deletion: ${fileName}`); // Log the start of the deletion
        const url = `https://${BUNNY_HOSTNAME}/${BUNNY_STORAGE_ZONE_NAME}/${fileName}`;

        const headers = {
            'AccessKey': BUNNY_ACCESS_KEY,
            'Content-Type': 'application/octet-stream'
        };

        const response = await axios.delete(url, { headers });
        logToFile1(`File deleted successfully: ${fileName}`); // Log successful deletion
        return response.data;
    } catch (error) {
        logToFile1(`Error deleting file: ${error.message}`); // Log error
        // console.error('Error deleting file:', error);
        // throw error;  // Rethrow or handle as necessary
    }
};




const bunnyCreateCollection = async (unique_file_name) => {
  try {

    // Construct the API URL
    const url = `https://video.bunnycdn.com/library/${BUNNY_LIBRARY_ID}/collections`;

    // Payload for the request
    const payload = {
      name: unique_file_name,
    };

    // Make the POST request to the Bunny CDN API
    const response = await axios.post(url, payload, {
      headers: {
        'Accesskey': BUNNY_STREAM_ACCESS_KEY,
        'Accept': 'application/json',
        'Content-Type': 'application/*+json',
      },
    });

    // Extract collection ID from the response
    const collection_id = response.data.guid;
    return collection_id;
  } catch (error) {
    console.error('Error creating collection:', error.message);
    throw error; // Or handle it as needed
  }
};


const bunnyCreateVideo = async (collection_id) => {
  try {

    // Construct the API URL
    const url = `https://video.bunnycdn.com/library/${BUNNY_LIBRARY_ID}/videos`;
    
    // Generate a unique video ID using userId and a random suffix (similar to PHP's uniqid())
    const uniquePrefixId = 'video_' + Date.now().toString(36) + Math.random().toString(36).substr(2, 9); 

    // Payload for the request
    const payload = {
      collectionId: collection_id,
      title: uniquePrefixId,
    };

    // Make the POST request to the Bunny CDN API
    const response = await axios.post(url, payload, {
      headers: {
        'Accesskey': BUNNY_STREAM_ACCESS_KEY,
        'Accept': 'application/json',
        'Content-Type': 'application/*+json',
      },
    });

    // Extract collection ID from the response
    const video_id = response.data.guid;
    return video_id;
  } catch (error) {
    console.error('Error creating collection:', error.message);
    throw error; // Or handle it as needed
  }
};


const getBunnyVideoInfo = async (video_id) => {
  try {

    // Construct the API URL
    const url = `https://video.bunnycdn.com/library/${BUNNY_LIBRARY_ID}/videos/${video_id}`;
    
    const response = await axios.get(url, {
      headers: {
        'Accesskey': BUNNY_STREAM_ACCESS_KEY,
        'Accept': 'application/json',
      }
    });

    // Extract collection ID from the response
    return response.data;
  } catch (error) {
    console.error('Error creating collection:', error.message);
    throw error; // Or handle it as needed
  }
};



// FOR BUNNY - END

// Controller to get all ads based on role
const getAds = async (req, res) => {

  try {
      
      // Access the Authorization token from the request headers
    const authHeader = req.headers['authorization']; // Get the 'Authorization' header
    if (!authHeader) {
      return res.status(401).json({ message: "Unauthorized Access" });
    }
    const accessToken = authHeader.split(' ')[1];  //Extract the token (it will be in the form "Bearer <token>")
    const decodedData = jwt.verify(accessToken, process.env.JWT_SECRET_KEY); // Verify and decode the token
    const user_id = decodedData.user_id; // Assuming 'user_id' is stored in the payload of the token 

    let query;
    let params = [];

    // If the role is admin, fetch all moderators created by the admin
    query = `SELECT * FROM event_ads WHERE user_id = ?`;
    params.push(user_id); // Pass the admin's ad_id for filtering

    const [event_ads] = await db.query(query, params); // Execute the query with appropriate parameters

    res.status(200).json(event_ads); // Send the ads as a JSON response
  } catch (error) {
    res.status(500).json({
      message: "An error occurred while fetching the ads",
      error,
    });
  }
};


const addEventAd = async (req, res) => {
  try {
    // Validate form data
    const { ad_name, ad_url, media_type, video_id=null } = req.body;
    // const media = req.files ? req.files.media : null; // Handle file upload

    if (!ad_name || !media_type) {
      return res.status(400).json({ message: "Ad Name, and media type are required!" });
    }
    
    // Access the Authorization token from the request headers
    const authHeader = req.headers['authorization']; // Get the 'Authorization' header
    if (!authHeader) {
      return res.status(401).json({ message: "Unauthorized Access" });
    }
    const accessToken = authHeader.split(' ')[1];  //Extract the token (it will be in the form "Bearer <token>")
    const decodedData = jwt.verify(accessToken, process.env.JWT_SECRET_KEY); // Verify and decode the token
    const user_id = decodedData.user_id; // Assuming 'user_id' is stored in the payload of the token 
    
    // File upload and deletion handling (one by one)
    let mediaUrl = null;
    let thumbnail_media_url = null;
    let mediaType = 'image'; // Default type to 'image'
    
    const file_save_prefix_folder='eu'+user_id+'/ads';
    
    if(media_type=='image')
    {
        if (req.files['media']) {
          const mediaPath = req.files['media'][0].path;
          const mediaName = req.files['media'][0].filename;
          const mediaType = req.files['media'][0].mimetype.split('/')[0];
        
          logToFile1(`Starting upload for media: ${mediaName}`);  // Log the start of the upload
          mediaUrl = await uploadFileToBunny(mediaName, mediaPath, file_save_prefix_folder);
          logToFile1(`media uploadedMediaUrl: ${mediaUrl}`);
          
          thumbnail_media_url=mediaUrl;
        
          // Log file deletion
          logToFile1(`Scheduled deletion for media: ${mediaPath}`); // Log deletion scheduling
          await fs.promises.unlink(mediaPath);  // Wait for deletion of file
          logToFile1(`Deleted file: ${mediaPath}`);
        }
    }
    else 
    {
        thumbnail_media_url=BUNNY_STREAM_BASE_URL+'/'+video_id+'/thumbnail.jpg';
    }
    

    // Insert the new ad post into the database with all the provided values
    const query = `
      INSERT INTO event_ads (
        user_id, ad_name, ad_url, media_url, thumbnail_media_url, media_file_type, bunny_video_id
      ) VALUES (?, ?, ?, ?, ?, ?, ?)
    `;

    await db.query(query, [
      user_id, ad_name, ad_url, mediaUrl, thumbnail_media_url, media_type, video_id
    ]);

    // Return success response
    return res.status(201).json({
      message: 'Ad post created successfully!',
    });
  } catch (error) {
    console.error(error);
    return res.status(500).json({ message: 'Server error. Unable to create ad post.',error:error.message });
  }
};


const updateEventAd = async (req, res) => {
  const { ad_name, ad_url, media_type=null, video_id = null } = req.body;
  const adId = req.params.id; // Get the ad ID from the URL parameter
  
  try {
      
    // Access the Authorization token from the request headers
    const authHeader = req.headers['authorization']; // Get the 'Authorization' header
    if (!authHeader) {
      return res.status(401).json({ message: "Unauthorized Access" });
    }
    const accessToken = authHeader.split(' ')[1];  //Extract the token (it will be in the form "Bearer <token>")
    const decodedData = jwt.verify(accessToken, process.env.JWT_SECRET_KEY); // Verify and decode the token
    const user_id = decodedData.user_id; // Assuming 'user_id' is stored in the payload of the token 
      
    // Check user authentication to perform action - start
    const [userCheck] = await db.query("SELECT role FROM users WHERE id = ? LIMIT 1", [user_id]);
    if (userCheck.length === 0) {
      return res.status(404).json({ message: "User not found" });
    }
    
    const userRole = userCheck[0].role;
    
    if (userRole != 'super_admin') {
        
    // Fetch the event from the DB using eventId to get event_hash_id
    const checkExistenceQuery = 'SELECT id FROM event_ads WHERE id = ? AND user_id = ? LIMIT 1';
    const [checkExistenceResult] = await db.query(checkExistenceQuery, [adId,user_id]);

    // Check if the event exists
    if (checkExistenceResult.length === 0) {
      return res.status(404).json({ message: "Ad not found or you are not authorize to take this action" });
    }    
        
    }
    // Check user authentication to perform action - start   
      
      
    // Step 1: Fetch the existing ad data by ad_id
    const adQuery = 'SELECT * FROM event_ads WHERE id = ?';
    const [adResult] = await db.query(adQuery, [adId]);

    // Check if the ad exists
    if (adResult.length === 0) {
      return res.status(404).json({ message: "Ad not found" });
    }
    
    let mediaUrl = null
    let thumbnail_media_url = null
    let mediaType = null
    
    const file_save_prefix_folder = 'eu' + user_id + '/ads';
    
    if(media_type)
    {
        // Step 2: Handle file upload and deletion (if a new media is uploaded)
        if (media_type === 'image' && req.files['media']) {
          const mediaPath = req.files['media'][0].path;
          const mediaName = req.files['media'][0].filename;
    
          logToFile1(`Starting upload for media: ${mediaName}`);
          mediaUrl = await uploadFileToBunny(mediaName, mediaPath, file_save_prefix_folder);
          logToFile1(`media uploadedMediaUrl: ${mediaUrl}`);
          
          thumbnail_media_url = mediaUrl; // In case of image, use the same URL for thumbnail
    
          // Log file deletion
          logToFile1(`Scheduled deletion for media: ${mediaPath}`);
          await fs.promises.unlink(mediaPath);
          logToFile1(`Deleted file: ${mediaPath}`);
        } else if (media_type === 'video' && video_id) {
          // If it's a video, update the thumbnail URL using the video_id
          thumbnail_media_url = `${BUNNY_STREAM_BASE_URL}/${video_id}/thumbnail.jpg`;
        }
        
        // delete - start
        let file_url=adResult[0].media_url;
        if(file_url)
        {
            let fileName = file_url.replace(BUNNY_CDN_BASE_URL+'/', '');
            // only for images - not work for videos
            await deleteFileFromBunny(fileName);
        }
        // delete - start
        
        
    }
    

    // Step 3: Update the ad data
    let updateFields = [];
    let values = [];

    // Check for each field and add it to the update query if provided
    if (ad_name) {
      updateFields.push("ad_name = ?");
      values.push(ad_name);
    }
    if (ad_url) {
      updateFields.push("ad_url = ?");
      values.push(ad_url);
    }
    if (media_type) {
      updateFields.push("media_file_type = ?");
      values.push(media_type);
    }
    if (mediaUrl) {
      updateFields.push("media_url = ?");
      values.push(mediaUrl);
    }
    if (thumbnail_media_url) {
      updateFields.push("thumbnail_media_url = ?");
      values.push(thumbnail_media_url);
    }
    if (video_id) {
      updateFields.push("bunny_video_id = ?");
      values.push(video_id);
    }

    // Only proceed if there are fields to update
    if (updateFields.length === 0) {
      return res.status(400).json({ message: "No data to update" });
    }

    // Add ad ID to the values for the WHERE clause
    values.push(adId);

    // SQL query to update the ad in the database
    const query = `UPDATE event_ads 
                   SET ${updateFields.join(", ")} 
                   WHERE id = ?`;

    const [result] = await db.query(query, values);

    // Check if the ad was updated
    if (result.affectedRows === 0) {
      return res.status(404).json({ message: "Ad not found or not authorized to update" });
    }

    // Step 4: Return the success response
    return res.status(200).json({ message: "Ad updated successfully" });
  } catch (error) {
    console.error("Error updating ad:", error);
    return res.status(500).json({ message: "Server error. Unable to update ad post.", error: error.message });
  }
};


// Controller to get an event by event_url_slug
const getVideoId = async (req, res) => {
  // Get the user_id from the query parameters
    const { user_id } = req.query;

  try {
    // Query the database to get the event by its event_url_slug
    const query = "SELECT * FROM users WHERE id = ?";
    const [user] = await db.query(query, [user_id]);

    if (user.length === 0) {
      return res.status(404).json({ message: "User not found" });
    }
    
    let bunny_collection_id=user[0].bunny_collection_id;
    let user_hash_id=user[0].user_hash_id;
    
    if(!user_hash_id)
    {
        // Generate a unique hash for the screen
        user_hash_id = 'eu'+user_id+'-'+generateUniqueHashId(); 
    }
    
    if(!bunny_collection_id)
    {
       bunny_collection_id=await bunnyCreateCollection(user_hash_id);
    }
    
    if(!user[0].bunny_collection_id || !user[0].user_hash_id)
    {
        // Query to update the 'is_favourite' field for the specified post_id
        const query = "UPDATE users SET user_hash_id = ?, bunny_collection_id = ? WHERE id = ?";
        const result = await db.query(query, [user_hash_id, bunny_collection_id, user_id]);
    
        // Check if the post was found and updated
        if (result[0].affectedRows === 0) {
        //   return res.status(404).json({ message: "Post not found" });
        }
    }
    
    
    const video_id=await bunnyCreateVideo(bunny_collection_id);
    
    // Calculate expiration_time (in seconds) for the signature
    const expiration_time = Math.floor(new Date().getTime() / 1000) + 200000; // 200000 seconds from now

    // Generate the presigned_signature using the bunnyVideoCalculateSignature function
    const presigned_signature = bunnyVideoCalculateSignature(BUNNY_LIBRARY_ID, BUNNY_STREAM_ACCESS_KEY, expiration_time, video_id);

    // Return the user details as a JSON response
    res.status(200).json({video_id, presigned_signature});
  } catch (error) {
    console.error("Error fetching user by URL slug:", error);
    res.status(500).json({
      message: "An error occurred while fetching the event",
      error: error.message, // Send the actual error message
    });
  }
};


// Webhook endpoint for video processing updates
const updateVideoWebhook = async (req, res) => {
  const json_data = req.body; // Express automatically parses JSON payload
  console.log(json_data); // Log the incoming data for debugging
//   logToFile1(json_data);
  logToFile1(`Video Webhook: ${JSON.stringify(json_data)}`); // Log start of the upload
  
  const bunny_video_id = json_data.VideoGuid;
  const video_status = json_data.Status;
  const update = {};
  const values = [];  // Initialize the values array to store the values for the SQL query
  const updateFields = [];

  if (video_status === 3) {
      
      try {
          
    // Video is processed and ready for further actions
    const result_video = await getBunnyVideoInfo(bunny_video_id);

    if (result_video) {
      // Assuming `availableResolutions` is a comma-separated string
      const availableResolutions = result_video.availableResolutions;
      const resolutions = availableResolutions.split(',');

      let max_resolution = 0;

      // Loop through resolutions and find the maximum
      resolutions.forEach((resolution) => {
        const resolutionValue = parseInt(resolution.replace('p', ''), 10);
        if (resolutionValue > max_resolution) {
          max_resolution = resolutionValue;
        }
      });

      // As Bunny only produces max 720p video
      if (max_resolution > 720) {
        max_resolution = 720;
      }

    //   update.max_resolution_height = max_resolution;
    updateFields.push('bunny_video_max_resolution_height');
      values.push(max_resolution);
      
      // Mark as processing complete
    updateFields.push('is_bunny_video_processing_complete');
    values.push('yes');
    
    const video_file_mp4_url=BUNNY_STREAM_BASE_URL+'/'+bunny_video_id+'/play_'+max_resolution+'p.mp4';
    
     // Mark as processing complete
    updateFields.push('media_url');
    values.push(video_file_mp4_url);
    
    // SQL query to update the video information directly in the database
    const query = `UPDATE event_posts
                   SET ${updateFields.map((field) => `${field} = ?`).join(", ")}
                   WHERE bunny_video_id = ?`;  // Ensure you're updating by bunny_video_id
    values.push(bunny_video_id);
    
    
      const [result] = await db.query(query, values);

      if (result.affectedRows > 0) {
        res.status(200).send({ message: 'Video processed successfully' });
      } else {
        res.status(500).send({ message: 'Error updating video' });
      }
    
    }
    else
    {
        res.status(400).send({ message: 'Video info not found on bunny' });
    }
    
    } catch (error) {
      console.error("Error executing query:", error);
      res.status(500).send({ message: 'Database update error', error: error.message });
    }
  } else {
    res.status(200).send({ message: 'Video status is not completed yet' });
  }
  
};  


// Controller to delete an existing event ad by its ID
const deleteEventAd = async (req, res) => {
  const { id } = req.params; // Get the event_ad_id from the URL params

  if (!id) {
    return res.status(400).json({ message: "Event Ad ID is required" });
  }

  try {
      
      // Access the Authorization token from the request headers
    const authHeader = req.headers['authorization']; // Get the 'Authorization' header
    if (!authHeader) {
      return res.status(401).json({ message: "Unauthorized Access" });
    }
    const accessToken = authHeader.split(' ')[1];  //Extract the token (it will be in the form "Bearer <token>")
    const decodedData = jwt.verify(accessToken, process.env.JWT_SECRET_KEY); // Verify and decode the token
    const user_id = decodedData.user_id; // Assuming 'user_id' is stored in the payload of the token 
    
    // Check user authentication to perform action - start
    const [userCheck] = await db.query("SELECT role FROM users WHERE id = ? LIMIT 1", [user_id]);
    if (userCheck.length === 0) {
      return res.status(404).json({ message: "User not found" });
    }
    
    const userRole = userCheck[0].role;
    
    if (userRole != 'super_admin') {
        
    // Fetch the event from the DB using eventId to get event_hash_id
    const checkExistenceQuery = 'SELECT id FROM event_ads WHERE id = ? AND user_id = ? LIMIT 1';
    const [checkExistenceResult] = await db.query(checkExistenceQuery, [id,user_id]);

    // Check if the event exists
    if (checkExistenceResult.length === 0) {
      return res.status(404).json({ message: "Ad not found or you are not authorize to take this action" });
    }    
        
    }
    // Check user authentication to perform action - start   
      
      
    // Ensure the event ad exists before attempting to delete
    const checkQuery = `SELECT * FROM event_ads WHERE id = ?`;
    const [existingEventAd] = await db.query(checkQuery, [id]);

    if (existingEventAd.length === 0) {
      return res.status(404).json({ message: "Event Ad not found for the provided ID!" });
    }
    
    // delete - start
    let file_url=existingEventAd[0].media_url;
    if(file_url)
    {
        let fileName = file_url.replace(BUNNY_CDN_BASE_URL+'/', '');
        // only for images - not work for videos
        await deleteFileFromBunny(fileName);
        // delete - end
    }
    // delete - end

    // Delete the event ad from the event_ads table
    const deleteQuery = `DELETE FROM event_ads WHERE id = ?`;
    await db.query(deleteQuery, [id]);

    res.status(200).json({ message: "Event Ad deleted successfully" });
  } catch (error) {
    res.status(500).json({
      message: "An error occurred while deleting the Event Ad",
      error: error.message,
    });
  }
};


module.exports = { getAds, addEventAd, updateEventAd, deleteEventAd, getVideoId, updateVideoWebhook};
