
process.env.JWT_SECRET = "kkjkjjew99";

//process.env.MONGODB_URI = "mongodb://127.0.0.1:27017/newCafe"

//process.env.MONGODB_URI="mongodb+srv://agode:agode1234@cluster0.zgsgsux.mongodb.net/agode"


process.env.MONGODB_URI="mongodb+srv://zad:zad1234@cluster0.a8cglje.mongodb.net/newCafe"

require('dotenv').config(); // Make sure this is at the top

const express = require('express');
const path = require('path');
const connectDB = require('./config/db');
const cartRoutes = require('./routes/cartRoutes'); // Import cart routes
const bcrypt = require('bcryptjs');
const app = express();
const ensureAuthenticated = require('./middleware/authMiddleware');
const session = require('express-session');
const router = express.Router();
const { login,logout } = require('./controllers/authController');
const sessionUser=require('./middleware/sessionUser')
const cookieParser = require('cookie-parser'); // Import cookie-parser
const jwt = require("jsonwebtoken");


 
const checkOrCreateDeviceId = require('./middleware/checkOrCreateDeviceId'); 
app.use(cookieParser()); // Middleware to parse cookies


// Middleware for parsing request bodies
// app.use(express.json());
// app.use(express.urlencoded({ extended: true }));

app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));

// const cors = require('cors');
// app.use(cors());
// const basePath = path.dirname(process.execPath);

// app.set('views', path.join(basePath, 'frontend', 'views'));
// app.use(express.static(path.join(basePath, 'frontend', 'public')));


// Debugging: Log the resolved path for the views directory
// console.log('Views Directory:', path.join(basePath, 'frontend', 'views'));
// console.log('EJS Module Path:', require.resolve('ejs'));

//Set the views directory to the frontend/views folder
app.set('views', path.join(__dirname, '../frontend/views'));
app.use(express.static(path.join(__dirname, '../frontend/public')));


app.set('view engine', 'ejs');



// Import routes
const ejsRoutes = require('./routes/ejsRoutes');





const MongoStore = require('connect-mongo'); // Store sessions in MongoDB

// Session Middleware
app.use(
  session({
    secret: process.env.SESSION_SECRET || 'your_secret_key',
    resave: false,
    saveUninitialized: false, // Only save sessions when modified
    store: MongoStore.create({
      mongoUrl: process.env.MONGODB_URI, // MongoDB URI from environment
      ttl: 24 * 60 * 60, // Session expiration in seconds (1 day here)
    }),
    cookie: {
      maxAge: 24 * 60 * 60 * 1000, // 1 day in milliseconds
      secure: false, // Set to true if you’re using HTTPS
      httpOnly: true, // Helps mitigate XSS
    },
  })
);








const User = require('./models/User');
const nodemailer = require('nodemailer');



const generateResetToken = (userId) => {
  return jwt.sign({ id: userId }, process.env.JWT_SECRET, { expiresIn: '1h' });
};

// Forgot password endpoint
// require("dotenv").config();
// const express = require("express");
// const nodemailer = require("nodemailer");
// const jwt = require("jsonwebtoken");


// Forgot password route
const Device = require("./models/Device");

app.get("/delete-devices", async function (req, res) {
  try {
    await Device.deleteMany(); // Deletes all documents in the Device collection
    res.send("All devices have been deleted successfully!");
  } catch (error) {
    console.error("Error deleting devices:", error);
    res.status(500).send("An error occurred while deleting devices.");
  }
});


app.use(checkOrCreateDeviceId);



router.post("/forgot-password", async (req, res) => {
  const email=req.body.email;
    console.log(email); // For debugging; remove in production

    try {
        const user = await User.findOne({ email });
        if (!user) {
            return res.status(404).json({ message: "User not found" });
        }

        // Generate and save reset token
        const resetToken = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: "1h" });
        user.resetPasswordToken = resetToken;
        user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
        await user.save();

        // Email configuration
        const transporter = nodemailer.createTransport({
            host: "mail.cybeerstock.com",
            port: 465,
            secure: true,
            auth: {
                user: 'support@cybeerstock.com',
                pass: 'cybeer@12345@tech'
            },
        });

        const resetLink = `https://reejeb.com/reset-password-page?token=${resetToken}`;
        const mailOptions = {
            from: 'support@cybeerstock.com',
            to:email,
            subject: "Password Reset",
            text: `Click the link to reset your password: ${resetLink}`,
        };

        await transporter.sendMail(mailOptions);
        console.log("Reset link sent to your email", resetLink);
        res.status(200).json({ message: "Reset link sent to your email" });
    } catch (error) {
        console.error("Error sending forgot password email:", error.message);
        res.status(500).json({ message: "Server error" });
    }
});




router.post('/reset-password', async (req, res) => {
  const { token, newPassword } = req.body;

  console.log(req.body);
  try {
    // Find the user by reset token and check expiration
    const user = await User.findOne({
      resetPasswordToken: token,
      resetPasswordExpires: { $gt: Date.now() },
    });

    if (!user) {
      return res.status(400).json({ message: 'Invalid or expired token' });
    }

    // Hash the new password
   // const hashedPassword = await bcrypt.hash(newPassword, 10);
    let hashedPassword;
  
      const salt = await bcrypt.genSalt(10);
      hashedPassword = await bcrypt.hash(newPassword, salt);
   
    user.password = hashedPassword;
    user.resetPasswordToken = undefined;
    user.resetPasswordExpires = undefined;
    await user.save();

    res.status(200).json({ message: 'Password reset successfully' });
  } catch (error) {
    res.status(500).json({ message: 'Server error' });
  }
});




















router.get('/login', (req, res) => {
  res.render('login');
});










const fs = require('fs').promises;

const vCardsJS = require('vcards-js');
//const axios = require('axios');
const VCard=require('./models/VCard')


app.post('/upload', async (req, res) => {
  try {
      const base64Data = req.body.image.replace(/^data:image\/jpeg;base64,/, "");
      const imageBuffer = Buffer.from(base64Data, 'base64'); // Create buffer

      console.log("coming form front end");
      const keyFilePath = './backend/vs.json';


      const extractedText = await detectTextWithLineBreaks(imageBuffer); // Pass buffer
      if (extractedText) {
        const extractedData = extractQuantityPrice(extractedText);
        //processExtractedData(extractedData);
         
        res.json({
          status: 'success',
          data: extractedData,
          message: 'Text extracted successfully', // Optional message
      });
  

      } else {
        
        res.status(400).json({ // Send JSON error response
          status: 'error',
          message: "No text found in the image or processing error.",
      });
      
      }
  } catch (error) {
      console.error("Error processing image:", error);
      res.status(500).send("Error processing image.");
  }
});


   


// app.post('/api/location', (req, res) => {
//   const { latitude, longitude } = req.body;

//   console.log('Received GPS coordinates:', latitude, longitude);

//   // You can store the data or process it further
//   res.send({ message: 'Location received' });
// });



// Route to generate and serve vCard
app.get('/vcards/:id', async(req, res) => {
    const vCard = vCardsJS();

  

    const info =  await VCard.findOne({ id: req.params.id });

//console.log(vCard);
    // Set vCard properties
    vCard.firstName = info.firstName;
    vCard.lastName = info.lastName;
    vCard.organization = info.organization;
    vCard.title = info.title;
  
    vCard.email = info.email;
     vCard.url = info.url;
    vCard.note = info.note; 
     vCard.cellPhone=info.workPhone; 
     vCard.workPhone = info.workPhone2 ? info.workPhone2.toString() : '';
     vCard.workUrl= info.map;

 //  VCard.socialUrls= { facebook: 'HTTPS://FB.COM', linkedIn: 'HTTPS://FBI.COM', twitter: '', flickr: '' };


    try {
        // Fetch the image as a buffer
      // const response = await axios.get(`https://cybeerstock.com${info.image_url}`, {
      //  //   const response = await axios.get(`http://localhost:5000${info.image_url}`, {
     
      //   //  responseType: 'arraybuffer',
      // });
      

        // Convert the image to base64
     //   const imageBase64 = Buffer.from(response.data).toString('base64');

        // Attach the image as base64 (inline image)
    //    vCard.photo.embedFromString(imageBase64, 'image/jpeg');
    } catch (error) {
        console.error('Failed to fetch image:', error.message);
    }

    // Send vCard as a file
    const vCardString = vCard.getFormattedString();

    let rawVCard = vCard.getFormattedString();

    // Append custom properties

//console.log("card is", rawVCard);
const additionalFields =
 `ADR;CHARSET=UTF-8:${info.address}\nURL;CHARSET=UTF-8:${info.map}\n`;

rawVCard = rawVCard.replace('END:VCARD', additionalFields + 'END:VCARD');
console.log("card is note is", vCard.note);
console.log("vcard is:",rawVCard);
    res.setHeader('Content-Type', 'text/vcard; charset=utf-8'); // MIME type for vCard
    res.setHeader('Content-Disposition', `inline; filename="${ info.firstName}.vcf"`); // Suggests inline display
    res.send(rawVCard);
});











// Add static route for login
router.get('/', (req, res) => {
  res.render('login'); // Render the login view (login.ejs or similar)
});

// POST /api/auth/login - Handle user login
router.post('/api/auth/login', login); // Handle login
router.post('/api/auth/logout', logout); // Handle logout

// Apply the router to the main app
app.use('/', router); // This makes the routes accessible






// Middleware to make session user available in EJS templates
app.use((req, res, next) => {
  res.locals.user = req.session.user;
  next();
});






// Connect to MongoDB
connectDB();

















// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Serve static files
app.use('/uploads', express.static(path.join(__dirname, '/uploads')));

app.use(express.static(path.join(__dirname, '../frontend/public')));
// Serve static files from "frontend/public"



//app.use(sessionUser);
app.use('/', ejsRoutes);


// Import the routes initializer
const initializeRoutes = require('./routes');

// Initialize all routes
initializeRoutes(app);

// Routes for serving HTML pages
const pages = [
 // { route: '/', file: 'new-transaction.html', auth: true },
  //{ route: '/login', file: 'index.html'},
  { route: '/transaction', file: 'new-transaction.html' },
  { route: '/transactions', file: 'transactions.html' },
  { route: '/companies', file: 'companies.html' },
  { route: '/branches', file: 'branches.html', auth: true },
  { route: '/items', file: 'items.html', auth: true },
  { route: '/stock', file: 'stock.html' },
  { route: '/summary', file: 'summary.html' },
  { route: '/report', file: 'transaction-report.html', auth: true },
  { route: '/details', file: 'transactionDetails.html' },
  { route: '/customers', file: 'customers.html', auth: true },
  { route: '/expense', file: 'expense.html', auth: true },
  { route: '/dailySales', file: 'dailySales.html', auth: true },
  { route: '/user', file: 'user.html' },
  { route: '/alltotalsummary', file: 'totalSummary_All.html' },
  { route: '/dailytotalsummary', file: 'totalSummary_Daily.html' },
  { route: '/setting', file: 'setting.html' },
  { route: '/profit', file: 'profit.html' },
  { route: '/register', file: 'register.html' },
  { route: '/monthlyExpense', file: 'monthlyExpense.html' },
  { route: '/mergedData', file: 'mergedData.html' },
  { route: '/general', file: 'general.html' },
  { route: '/financialSummary', file: 'financeSummary.html' },
  { route: '/branchGroup', file: 'branchGroups.html' },
  { route: '/bankAccount', file: 'bankAccount.html' },
  { route: '/bankTransaction', file: 'bankTransaction.html' }
];

pages.forEach(({ route, file, auth }) => {
  if (auth) {
    app.get(route, ensureAuthenticated, (req, res) => {
      res.sendFile(path.join(__dirname, '../frontend/public', file));
    });
  } else {
    app.get(route, (req, res) => {
      res.sendFile(path.join(__dirname, '../frontend/public', file));
    });
  }
});

// Example of an API endpoint
app.get('/api/items', ensureAuthenticated, (req, res) => {
  res.json([
    { name: 'Item 1', code: 'ITEM001', price: 100 },
    { name: 'Item 2', code: 'ITEM002', price: 150 },
    { name: 'Item 3', code: 'ITEM003', price: 200 }
  ]);
});

// Start server
// const PORT = process.env.PORT || 5000;
// app.listen(PORT, () => {
//   console.log(`Server running on port ${PORT}`);
// });

const cron = require('node-cron');
const { getSummary } = require('./controllers/autoCalculationController');
const { saveBranchResultsToFinancialSummary } = require('./controllers/financialSummaryController');

// Schedule daily task
cron.schedule('55 23 * * *', async () => {
  console.log('Running daily sales aggregation...');
  try {
    const branchResults = await getSummary();
    await saveBranchResultsToFinancialSummary(branchResults);
    console.log('Daily sales aggregation completed.');
  } catch (error) {
    console.error('Error during daily sales aggregation:', error);
  }
});
async function runDailySalesAggregation() {
  console.log('Running daily sales aggregation...');
  try {
    const branchResults = await getSummary();
    await saveBranchResultsToFinancialSummary(branchResults);
    console.log('Daily sales aggregation completed.');
  }
  
  catch (error) {
    console.error('Error during daily sales aggregation:', error);
  }
}

// Call the function
//runDailySalesAggregation();


const permissionsConfig = require('./config/permission'); // Import permissions config
const Permission=require('./models/Permission')

const Role=require('./models/Role')
const seedPermissions = async () => {
  try {
  

    // Prepare permissions from the config
    const permissions = Object.entries(permissionsConfig).map(([key, description]) => ({
      name: key,
      description,
    }));

    // Insert permissions into the database
    await Permission.insertMany(permissions, { ordered: false });
    console.log('Permissions added successfully');
  } catch (error) {
    if (error.code === 11000) {
      console.error('Duplicate permissions skipped:', error.message);
    } else {
      console.error('Error seeding permissions:', error.message);
    }
  } finally {
    // Disconnect from the database
   
  }
};

// Run the seeding script//


//const Permission = require('./Permission2'); // Import the model
const PERMISSIONS_CATEGORIES = require('./config/permission2'); // Import the permissions

const savePermissionsToDb = async () => {
  try {
   

    // Iterate through PERMISSIONS_CATEGORIES and save each permission
    for (const categoryKey in PERMISSIONS_CATEGORIES) {
      const category = PERMISSIONS_CATEGORIES[categoryKey];
      const categoryName = category.name;
console.log('printing category:', category.name);
      for (const permissionKey in category.permissions) {
        const permissionName = permissionKey;
        const permissionDescription = category.permissions[permissionKey];

        // Check if the permission already exists
        const existingPermission = await Permission.findOne({ name: permissionName });
        if (existingPermission) {
          console.log(`Permission "${permissionName}" already exists. Skipping.`);
          continue;
        }

        // Save the permission
        const newPermission = new Permission({
          name: permissionName,
          description: permissionDescription,
          category: categoryName,
        });

        await newPermission.save();
        console.log(`Saved permission: ${permissionName} under category: ${categoryName}`);
      }
    
    
    
    
    }

    const permissions = await Permission.find({});

    // Create a new role
   

    const roleName = 'ADMIN';

    // Check if the role exists
    let role = await Role.findOne({ name: roleName });
    
    if (role) {
      // If the role exists, update permissions
      role.permission = permissions.map((p) => p._id);
      await role.save();
      console.log('Role updated:', role);
    } else {
      // If the role doesn't exist, create it
      role = new Role({
        name: roleName,
        permission: permissions.map((p) => p._id),
      });
      await role.save();
      console.log('New role created:', role);
    }
    


    console.log('All permissions saved successfully.');
   // mongoose.connection.close();
  } catch (error) {
    console.error('Error saving permissions to database:', error);
    //mongoose.connection.close();
  }
};


//savePermissionsToDb();

function replaceSimilarChars(text) {
  return text
    .replace(/o/gi, "0") // g for global (all occurrences), i for case-insensitive
    .replace(/Ο/gi, "0")//Greek: Ο (uppercase omicron) 
    .replace(/О/gi, "0")// Cyrillic: О (uppercase O)
    .replace(/a/g, "0")//  Latin lowercase "a"
    .replace(/а/g, "0")//  Cyrillic lowercase "а"
    .replace(/l/gi, "1")// 
    .replace(/ト/gi, "1")
    .replace(/г/gi, "1")
    .replace(/ו/gi, "1")
    .replace(/T/g, "1")
    .replace(/i/g, "1")
    .replace(/I/g, "1")
    .replace(/\|/g, "1")// vertical bar
    .replace(/\//gi, "1")
    .replace(/\\\\/g, "1")// backwared slash
    .replace(/z/gi, "2")// 
    .replace(/r/gi, "2")// 
    .replace(/З/gi, "3")//Cyrillic capital letter "Ze" (З)
    .replace(/나/gi, "4")
    .replace(/4/gi, "4")
    .replace(/ч/gi, "4")
    .replace(/s/gi, "5")
    .replace(/б/g, "6")
    .replace(/b/g, "6")
    .replace(/t/g, "7")
    .replace(/B/g, "8")
    .replace(/し/g, "C")
    .replace(/L/g, "C")
    .replace(/[cCСс]/g, "C");// // С (Cyrillic Capital 
        }

function extractQuantityPrice(text) {
 // const regex = /([a-zA-Z0-9]+)\s+([\d]+)\s+([\d]+)/g; // Matches code, quantity, price
//const regex = /([a-zA-Z0-9]+)\s*(?:,|(?:\s+))([\d]+)\s*(?:,|(?:\s+))([\d,.]+(?:\.\d+)?)/g;
// const regex = /[cC](\d+)\s+(\d+)\s+([\d.]+)/g; 
const regex = /[cC]\s*(\d+)(?:\s+(\d+))?(?:\s+(\d+))?/g;
const results = [];
  let match;
  console.log("send data is:", text);
  let replacedText='';
  if( text)
 { replacedText= replaceSimilarChars(text)}

 console.log("replaced text is:", replacedText);
  while ((match = regex.exec(replacedText)) !== null) {

    console.log("mach is",match);
      const code = match[1].trim();
      const quantity = parseInt(match[2], 10)||0;
      const price = parseInt(match[3], 10)||0;
      results.push({ code, quantity, price });
  }
  console.log("data is",results);
  return results;
}


function processExtractedData(extractedData)
 {

  if (extractedData.length === 0) {
      console.log("No valid data found in the input string.");
      return;
  }
  extractedData.forEach(item => {
      console.log(`Code: ${item.code}, Quantity: ${item.quantity}, Price: ${item.price}`);
  });

}





// Run the function
//savePermissionsToDb();
const vision = require('@google-cloud/vision');
const fsp = require('fs').promises;

async function detectTextWithLineBreaks1(imagePath, keyFilePath) {
    try {
        try {
            await fs.access(keyFilePath);
        } catch (err) {
            throw new Error(`Key file not found: ${keyFilePath}`);
        }

        const client = new vision.ImageAnnotatorClient({ keyFilename: keyFilePath });

        const [result] = await client.documentTextDetection(imagePath); // Use documentTextDetection
        const fullTextAnnotation = result.fullTextAnnotation;

        if (!fullTextAnnotation) {
            console.log('No text found in the image.');
            return null;
        }

        const pages = fullTextAnnotation.pages;
        if (!pages || pages.length === 0) {
            console.log('No pages found in the image.');
            return null
        }

        const blocks = pages[0].blocks;
        if (!blocks || blocks.length === 0) {
            console.log('No text blocks found in the image.');
            return null;
        }


        let formattedText = "";
        for (const block of blocks) {
            for (const paragraph of block.paragraphs) {
                let lineText = "";
                for (const word of paragraph.words) {
                  const wordText = word.symbols.map(s => s.text).join('');
                  lineText += wordText + " ";
                }
                formattedText += lineText.trim() + "\n"; // Add newline after each line
            }
        }
        return formattedText.trim();

    } catch (error) {
        console.error('Error:', error);
        return null;
    }
}

async function main() {
    const imagePath = './backend/uploads/m4.jpg';
    const keyFilePath = './backend/vs.json';

    const extractedText = await detectTextWithLineBreaks1(imagePath, keyFilePath);
    const extractedData = extractQuantityPrice(extractedText);
    
   
 
    processExtractedData(extractedData);
    if (extractedText) {
        console.log("Extracted Text:\n", extractedText);
       

    } else {
        console.log("Text extraction failed or no text found.");
    }
}

//main();



//const keyFilePath = './backend/vs.json'; // Path to your service account key file
const keyFilePath = './backend/FCMKEY.json';
const client = new vision.ImageAnnotatorClient({ keyFilename: keyFilePath });

async function detectTextWithLineBreaks(imageBuffer) { // Accept imageBuffer
    try {
        const [result] = await client.documentTextDetection(imageBuffer); // Pass buffer directly
        const fullTextAnnotation = result.fullTextAnnotation;

        if (!fullTextAnnotation) {
            console.log('No text found in the image.');
            return null;
        }

        // ... (rest of the text extraction logic remains the same)
        const pages = fullTextAnnotation.pages;
        if (!pages || pages.length === 0) {
            console.log('No pages found in the image.');
            return null
        }

        const blocks = pages[0].blocks;
        if (!blocks || blocks.length === 0) {
            console.log('No text blocks found in the image.');
            return null;
        }


        let formattedText = "";
        for (const block of blocks) {
            for (const paragraph of block.paragraphs) {
                let lineText = "";
                for (const word of paragraph.words) {
                    const wordText = word.symbols.map(s => s.text).join('');
                    lineText += wordText + " ";
                }
                formattedText += lineText.trim() + "\n"; // Add newline after each line
            }
        }
        return formattedText.trim();


    } catch (error) {
        console.error('Error:', error);
        return null;
    }
}


//forGPs


const http = require('http');
const { Server } = require('socket.io');

const server = http.createServer(app);

const io = new Server(server, {
  cors: {
    origin: '*',
    methods: ['GET', 'POST'],
  },
});
 

let gpsData = {};

// Endpoint to receive GPS data from the holder
app.post('/api/location', (req, res) => {
  // req.body={
  //   "deviceId": "device2",
  //   "latitude": 9.012379,
  //   "longitude": 38.756819
  // };

 
  const { deviceId, latitude, longitude } = req.body;
  if (!deviceId || !latitude || !longitude) {
    return res.status(400).json({ message: 'Invalid data' });
  }


console.log("Gps data is",req.body);

  // Update GPS data
  gpsData[deviceId] = { latitude, longitude };

  // Broadcast the updated location to all connected clients
  io.emit('locationUpdate', { deviceId, latitude, longitude });

  res.status(200).json({ message: 'Location updated successfully' });
});

// WebSocket connection
io.on('connection', (socket) => {
  console.log('A user connected:', socket.id);

  // Send the latest GPS data to the newly connected client
  socket.emit('initialData', gpsData);

  socket.on('disconnect', () => {
    console.log('A user disconnected:', socket.id);
  });
});

// Make io accessible globally for use in controllers if needed
global.io = io;







const admin = require('firebase-admin');
const serviceAccount ='./backend/FCMKEY.json';
async function initializeAndSendNotification() {
  // Initialize Firebase Admin SDK
  admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
  });

  try {
    // Send FCM message
    const message = {
      data: { // change 'data' to ' notification' if you want to send notification that popup as notification
        title: 'Welcome',
        body: 'This is a welcome message from cybeertech!',
      },
      // Replace with your actual FCM token
      token: 'fArZuc9NQ8qknOnZT65T23:APA91bFzhJa08IddPuU6AaWIoOOQqO_14AZO4A9Hceu6PyDWbYpsqaHisTIE3E2LfuhynhbyJ1Nowb_hHpBNb0qGPo7C44WzS2QvHDER5VxjHl3fGjCm8eE',
    };
    const response = await admin.messaging().send(message);
    console.log('Successfully sent message:', response);
  } catch (error) {
    console.log('Error sending message:', error);
  }
}

// Call the async function
//initializeAndSendNotification();








// Start server
const PORT2=5000;
server.listen(PORT2,'0.0.0.0', () => {
  console.log(`Server running on http://localhost:${PORT2}`);
});


