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');


// Helper function to write logs to a file
const logToFile1 = (message) => {
  const logMessage = `${new Date().toISOString()} - ${message}\n`;
  const logFilePath = path.join(__dirname, 'logs', 'server.log'); // Ensure the logs directory exists

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

  // Append log message to the file
  fs.appendFileSync(logFilePath, logMessage, 'utf8');
};

// 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';

// 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 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
  }
};

// FOR BUNNY - END


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


// Controller to get all users based on role
const getAllUsers = 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 
    
    // Fetch the role of the user from the database
    const roleQuery = `SELECT role FROM users WHERE id = ?`;
    const [userRoleResult] = await db.query(roleQuery, [user_id]);

    if (userRoleResult.length === 0) {
      return res.status(404).json({ message: "User not found" });
    }

    const role = userRoleResult[0].role; // Extract role from the result

    let query;
    let params = [];

    if (role === 'super_admin') {
      // If the role is super_admin, fetch all moderators and admins
      query = `SELECT * FROM users WHERE role IN ('admin')`;
    } else if (role === 'admin') {
      // If the role is admin, fetch all moderators created by the admin
      query = `SELECT * FROM users WHERE role = 'moderator' AND created_by = ?`;
      params.push(user_id); // Pass the admin's user_id for filtering
    } else {
      return res.status(403).json({
        message: "You do not have the required permissions to access this resource.",
      });
    }

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

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

// Controller to add a new user
const addUser = async (req, res) => {
  const { email, password } = req.body; // Extract email, password, and user_id from request body
  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  
    
    // Fetch the role of the current user from the database
    const roleQuery = `SELECT role FROM users WHERE id = ?`;
    const [userRoleResult] = await db.query(roleQuery, [user_id]);

    if (userRoleResult.length === 0) {
      return res.status(404).json({ message: "Current user not found" });
    }

    const currentUserRole = userRoleResult[0].role;

    // Determine the role of the new user based on the current user's role
    let newUserRole;
    if (currentUserRole === "admin") {
      newUserRole = "moderator";
    } else if (currentUserRole === "super_admin") {
      newUserRole = "admin";
    } else {
      return res.status(403).json({
        message: "You do not have the required permissions to add a new user",
      });
    }

    // Check if email already exists in the database
    const checkQuery = "SELECT * FROM users WHERE email = ?";
    const [existingUser] = await db.query(checkQuery, [email]);

    if (existingUser.length > 0) {
      return res.status(400).json({ message: "Email already exists" });
    }

    // Encrypt the password using bcrypt
    const hashedPassword = await bcrypt.hash(password, 10); // 10 is the salt rounds

    // Insert the new user into the database with the determined role
    const insertUserQuery  = `INSERT INTO users (email, password, role, created_by) 
                  VALUES (?, ?, ?, ?)`;

    const [userInsertResult]=await db.query(insertUserQuery , [email, hashedPassword, newUserRole, user_id]);
    
    
    // Get the id of the newly created ads group
    const lastInsertUserId = userInsertResult.insertId;
    
        // Generate a unique hash for the screen
    const user_hash_id = 'eu'+lastInsertUserId+'-'+generateUniqueHashId(); 
    
    const bunny_collection_id=await bunnyCreateCollection(user_hash_id);
    
    
    // Update the 'user_hash_id' and 'bunny_collection_id' for the newly created user
    const updateUserQuery = "UPDATE users SET user_hash_id = ?, bunny_collection_id = ? WHERE id = ?";
    await db.query(updateUserQuery, [user_hash_id, bunny_collection_id, lastInsertUserId]);

    // Insert new user details and create the user_details_pivot
    const insertUserDetailsQuery = `INSERT INTO user_details (created_by) VALUES (?)`;
    const [userDetailsInsertResult] = await db.query(insertUserDetailsQuery, [user_id]);

    const user_details_id = userDetailsInsertResult.insertId;

    const insertPivotQuery = `INSERT INTO user_details_pivot (user_id, user_details_id) 
                              VALUES (?, ?)`;
    await db.query(insertPivotQuery, [lastInsertUserId, user_details_id]);
    

    // Respond with success message
    res.status(201).json({ message: "User added successfully", role: newUserRole });
  } catch (error) {
    res.status(500).json({
      message: "An error occurred while adding the user",
      error,
    });
  }
};


const updateUser = async (req, res) => {
  const { email, password } = req.body; // Extract email and password from request body
  const userId = req.params.id; // Get the user 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   
    
    // Fetch the role of the current user from the database
    const roleQuery = `SELECT role FROM users WHERE id = ?`;
    const [userRoleResult] = await db.query(roleQuery, [user_id]);

    if (userRoleResult.length === 0) {
      return res.status(404).json({ message: "Current user not found" });
    }

    const currentUserRole = userRoleResult[0].role;

    // Determine the role of the new user based on the current user's role

    if (currentUserRole != "super_admin") {
        
    if (currentUserRole == "admin") {

    // Fetch the role of the current user from the database
    const adminCheckQuery = `SELECT id FROM users WHERE id = ? AND created_by = ?`;
    const [adminCheckResult] = await db.query(adminCheckQuery, [userId,user_id]);

    if (adminCheckResult.length === 0) {
      return res.status(403).json({
        message: "You do not have the required permissions to edit a new user",
        });
    }

    }else {
        return res.status(403).json({
        message: "You do not have the required permissions to edit a new user",
        });
    } 

    }
      
      
    let updateFields = [];
    let values = [];

    // Check if email is provided and is different from the current one
    if (email) {
      updateFields.push("email = ?");
      values.push(email);
    }

    // Check if password is provided, then hash it
    if (password) {
      const hashedPassword = await bcrypt.hash(password, 10); // Hash the password
      updateFields.push("password = ?");
      values.push(hashedPassword);
    }

    // Only update if there's at least one field (email or password) provided
    if (updateFields.length === 0) {
      return res.status(400).json({ message: "No data to update." });
    }

    // SQL query to update the user data by its ID
    const query = `UPDATE users 
                   SET ${updateFields.join(", ")} 
                   WHERE id = ?`;

    // Add the user ID at the end of the values
    values.push(userId);

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

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

    res.status(200).json({ message: "User updated successfully" });
  } catch (error) {
    console.error("Error updating user:", error);
    res.status(500).json({ message: "An error occurred while updating the user", error });
  }
};



const getUserDetails = 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 userId = decodedData.user_id; // Assuming 'user_id' is stored in the payload of the token    
      
    // Step 1: Fetch user details from the `user_details` table
    const userDetailsQuery = `
      SELECT 
        ud.id AS user_details_id, 
        ud.company_name, 
        ud.address, 
        ud.city, 
        ud.state, 
        ud.zip_code, 
        ud.phone_number, 
        ud.website_url, 
        ud.timezone, 
        ud.company_logo_url, 
        ud.favicon_url, 
        ud.thumbnail_url, 
        users.email 
      FROM user_details ud
      LEFT JOIN user_details_pivot udp ON ud.id = udp.user_details_id
      LEFT JOIN users ON udp.user_id = users.id
      WHERE udp.user_id = ?;
    `;
    
    const [userDetails] = await db.query(userDetailsQuery, [userId]);

    // Step 2: Check if user details exist
    if (userDetails.length === 0) {
      return res.status(404).json({ message: "User details not found" });
    }

    // Step 3: Return the user details with file URLs
    return res.status(200).json(userDetails[0]);

  } catch (error) {
    console.error("Error fetching user details:", error);
    res.status(500).json({
      message: "An error occurred while fetching the user details",
      error: error.message,
    });
  }
};


const updateUserDetails = async (req, res) => {
  const {
    company_name,
    address,
    city,
    state,
    zip_code,
    phone_number,
    website_url,
    timezone
  } = req.body;

  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 userId = decodedData.user_id; // Assuming 'user_id' is stored in the payload of the token 
    
    // Fetch user details from the DB to get user_details_id
    const userQuery = 'SELECT user_details_id FROM user_details_pivot WHERE user_id = ?';
    const [userResult] = await db.query(userQuery, [userId]);

    // Check if the user details exist
    if (userResult.length === 0) {
      return res.status(404).json({ message: "User details not found" });
    }

    const userDetailsId = userResult[0].user_details_id;
    
    // Get user hash 
    
    // Query the database to get the event by its event_url_slug
    const query = "SELECT user_hash_id FROM users WHERE id = ?";
    const [user] = await db.query(query, [userId]);

    if (user.length === 0) {
      return res.status(404).json({ message: "User not found" });
    }
    
    let user_hash_id=user[0].user_hash_id;
    
    const file_save_prefix_folder='eu'+userId+'/user-details-images';
    
    
    // Start Update

    let updateFields = [];
    let values = [];

    // If user details are provided, update them
    if (company_name) {
      updateFields.push("company_name = ?");
      values.push(company_name);
    }
    if (address) {
      updateFields.push("address = ?");
      values.push(address);
    }
    if (city) {
      updateFields.push("city = ?");
      values.push(city);
    }
    if (state) {
      updateFields.push("state = ?");
      values.push(state);
    }
    if (zip_code) {
      updateFields.push("zip_code = ?");
      values.push(zip_code);
    }
    if (phone_number) {
      updateFields.push("phone_number = ?");
      values.push(phone_number);
    }
    if (website_url) {
      updateFields.push("website_url = ?");
      values.push(website_url);
    }
    if (timezone) {
      updateFields.push("timezone = ?");
      values.push(timezone);
    }

    // File upload handling for company_logo, favicon_image, and thumbnail_image
    let uploadedCompanyLogoUrl = null;
    let uploadedFaviconUrl = null;
    let uploadedThumbnailUrl = null;

    // Handle company_logo file upload
    if (req.files['company_logo']) {
      const companyLogoPath = req.files['company_logo'][0].path;
      const companyLogoName = req.files['company_logo'][0].filename;

      logToFile1(`Starting upload for company_logo: ${companyLogoName}`);
      uploadedCompanyLogoUrl = await uploadFileToBunny(companyLogoName, companyLogoPath, file_save_prefix_folder);
      logToFile1(`company_logo uploadedCompanyLogoUrl: ${uploadedCompanyLogoUrl}`);

      // Log file deletion
      logToFile1(`Scheduled deletion for company_logo: ${companyLogoPath}`);
      await fs.promises.unlink(companyLogoPath); // Wait for deletion of file
      logToFile1(`Deleted file: ${companyLogoPath}`);

      updateFields.push("company_logo_url = ?");
      values.push(uploadedCompanyLogoUrl);
    }

    // Handle favicon_image file upload
    if (req.files['favicon_image']) {
      const faviconPath = req.files['favicon_image'][0].path;
      const faviconName = req.files['favicon_image'][0].filename;

      logToFile1(`Starting upload for favicon_image: ${faviconName}`);
      uploadedFaviconUrl = await uploadFileToBunny(faviconName, faviconPath, file_save_prefix_folder);
      logToFile1(`favicon_image uploadedFaviconUrl: ${uploadedFaviconUrl}`);

      // Log file deletion
      logToFile1(`Scheduled deletion for favicon_image: ${faviconPath}`);
      await fs.promises.unlink(faviconPath); // Wait for deletion of file
      logToFile1(`Deleted file: ${faviconPath}`);

      updateFields.push("favicon_url = ?");
      values.push(uploadedFaviconUrl);
    }

    // Handle thumbnail_image file upload
    if (req.files['thumbnail_image']) {
      const thumbnailPath = req.files['thumbnail_image'][0].path;
      const thumbnailName = req.files['thumbnail_image'][0].filename;

      logToFile1(`Starting upload for thumbnail_image: ${thumbnailName}`);
      uploadedThumbnailUrl = await uploadFileToBunny(thumbnailName, thumbnailPath, file_save_prefix_folder);
      logToFile1(`thumbnail_image uploadedThumbnailUrl: ${uploadedThumbnailUrl}`);

      // Log file deletion
      logToFile1(`Scheduled deletion for thumbnail_image: ${thumbnailPath}`);
      await fs.promises.unlink(thumbnailPath); // Wait for deletion of file
      logToFile1(`Deleted file: ${thumbnailPath}`);

      updateFields.push("thumbnail_url = ?");
      values.push(uploadedThumbnailUrl);
    }

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

    // Add user_details_id to the values for the update query
    values.push(userDetailsId);

    // SQL query to update the user details
    const updateQuery = `UPDATE user_details 
                   SET ${updateFields.join(", ")} 
                   WHERE id = ?`;

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

    // Check if the user details were updated
    if (update_result.affectedRows === 0) {
      return res.status(404).json({ message: "User details not found or not authorized to update" });
    }

    res.status(200).json({ message: "User details updated successfully" });
  } catch (error) {
    console.error("Error updating user details:", error);
    res.status(500).json({ message: "An error occurred while updating the user details", error: error.message });
  }
};



module.exports = { addUser, getAllUsers, updateUser, getUserDetails, updateUserDetails };
