const express = require('express');
const fs = require('fs');
const path = require('path');
const QRCode = require('qrcode');

const app = express();
const PORT = 3000;

// Body parser
app.use(express.json());

// Setup paths configurations dynamically
const publicDir = path.join(__dirname, 'public');
const assetsDir = path.join(publicDir, 'assets');
const configPath = path.join(__dirname, 'config.json');

const defaultPaths = {
    databaseFolder: "C:\\Users\\Dell\\OneDrive - Eratron.in\\Academic Files\\AQIS (2026-2027)\\Students Data Base",
    photoFolder: "C:\\Users\\Dell\\OneDrive - Eratron.in\\Academic Files\\AQIS (2026-2027)\\Students Photo AY (26-27)"
};

// Load or create local config.json for dynamic paths
let config = defaultPaths;
if (fs.existsSync(configPath)) {
    try {
        config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
    } catch (e) {
        console.error("Error reading config.json:", e);
    }
} else {
    fs.writeFileSync(configPath, JSON.stringify(defaultPaths, null, 2), 'utf8');
}

let dbDir = config.databaseFolder;
let photoDir = config.photoFolder;
let dataFile = path.join(dbDir, 'students.json');
let certsFile = path.join(dbDir, 'certificates_db.json');
let settingsFile = path.join(dbDir, 'settings_db.json');

// Helper: load JSON file safely
function loadJson(filePath, defaultValue = []) {
    try {
        if (fs.existsSync(filePath)) {
            const data = fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, '');
            return JSON.parse(data);
        }
    } catch (err) {
        console.error(`Error loading file ${filePath}:`, err);
    }
    return defaultValue;
}

// Helper: save JSON file safely
function saveJson(filePath, data) {
    try {
        const dir = path.dirname(filePath);
        if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
        fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
        return true;
    } catch (err) {
        console.error(`Error saving file ${filePath}:`, err);
        return false;
    }
}

// Ensure folders exist
if (!fs.existsSync(publicDir)) fs.mkdirSync(publicDir);
if (!fs.existsSync(assetsDir)) fs.mkdirSync(assetsDir, { recursive: true });
if (!fs.existsSync(dbDir)) fs.mkdirSync(dbDir, { recursive: true });

// Load default school assets if they exist
const defaultLogoSrc = "C:\\Users\\Dell\\OneDrive - Eratron.in\\Academic Files\\AQIS (2023-2024)\\ACADAMIC\\2023\\Logo.png";
const defaultSignSrc = "C:\\Users\\Dell\\OneDrive - Eratron.in\\Academic Files\\AQIS (2025-2026)\\Sanitary\\Sign.jpg";

try {
    if (fs.existsSync(defaultLogoSrc) && !fs.existsSync(path.join(assetsDir, 'logo.png'))) {
        fs.copyFileSync(defaultLogoSrc, path.join(assetsDir, 'logo.png'));
    }
    if (fs.existsSync(defaultSignSrc) && !fs.existsSync(path.join(assetsDir, 'signature.png'))) {
        fs.copyFileSync(defaultSignSrc, path.join(assetsDir, 'signature.png'));
    }
} catch (err) {
    console.error("Error copying default assets:", err);
}

const defaultSettings = {
    schoolName: "AL QALAM INTERNATIONAL SCHOOL",
    affiliation: "Affiliation No: 1931228 | School Code: 56183",
    motto: "\"Excellence in Education, Character and Service\"",
    address: "Perungulam, Ramanathapuram District, Tamil Nadu",
    mobile: "+91 8870689861",
    email: "alqalamschoolpgm@gmail.com",
    principalName: "Sheikh. Abdul Qudoos Azhari",
    designation: "Principal",
    academicYear: "2026–2027",
    certificatePrefix: "AQIS/2026-27/BC/",
    certificateCounter: 1
};

if (!fs.existsSync(settingsFile)) {
    saveJson(settingsFile, defaultSettings);
}

if (!fs.existsSync(certsFile)) {
    saveJson(certsFile, []);
}

// Serve static frontend files
app.use(express.static(publicDir));

// API: Get settings
app.get('/api/settings', (req, res) => {
    const settings = loadJson(settingsFile, defaultSettings);
    // Inject dynamic directories configs
    settings.photoFolder = photoDir;
    settings.databaseFolder = dbDir;
    res.json(settings);
});

// API: Save settings
app.post('/api/settings', (req, res) => {
    // 1. Update config.json if paths are changed
    if (req.body.databaseFolder || req.body.photoFolder) {
        config.databaseFolder = req.body.databaseFolder || config.databaseFolder;
        config.photoFolder = req.body.photoFolder || config.photoFolder;
        saveJson(configPath, config);
        
        // Update local pointers
        dbDir = config.databaseFolder;
        photoDir = config.photoFolder;
        dataFile = path.join(dbDir, 'students.json');
        certsFile = path.join(dbDir, 'certificates_db.json');
        settingsFile = path.join(dbDir, 'settings_db.json');
    }

    const current = loadJson(settingsFile, defaultSettings);
    
    // Clean folders paths out of main settings db file
    const cleanBody = { ...req.body };
    delete cleanBody.photoFolder;
    delete cleanBody.databaseFolder;

    const updated = { ...current, ...cleanBody };
    if (saveJson(settingsFile, updated)) {
        updated.photoFolder = photoDir;
        updated.databaseFolder = dbDir;
        res.json({ success: true, settings: updated });
    } else {
        res.status(500).json({ success: false, message: "Failed to save settings." });
    }
});

// API: Search students (by name, ID, Father, Class, Mobile, Section, EMIS)
app.get('/api/students', (req, res) => {
    const students = loadJson(dataFile, []);
    const query = (req.query.q || '').trim().toLowerCase();
    
    if (!query) {
        return res.json(students);
    }
    
    const results = students.filter(s => {
        const adm = s.AdmissionNo !== undefined && s.AdmissionNo !== null ? String(s.AdmissionNo).toLowerCase() : '';
        const name = s.StudentName !== undefined && s.StudentName !== null ? String(s.StudentName).toLowerCase() : '';
        const father = s.FatherName !== undefined && s.FatherName !== null ? String(s.FatherName).toLowerCase() : '';
        const mobile = s.Mobile !== undefined && s.Mobile !== null ? String(s.Mobile).toLowerCase() : '';
        const grade = s.Grade !== undefined && s.Grade !== null ? String(s.Grade).toLowerCase() : '';
        const section = s.Section !== undefined && s.Section !== null ? String(s.Section).toLowerCase() : '';
        const emis = s.EMISNo !== undefined && s.EMISNo !== null ? String(s.EMISNo).toLowerCase() : '';
        
        return adm.includes(query) || 
               name.includes(query) || 
               father.includes(query) || 
               mobile.includes(query) || 
               grade.includes(query) || 
               section.includes(query) || 
               emis.includes(query);
    });
    res.json(results.slice(0, 15)); // Limit to top 15 results for autocomplete
});

// API: Serve student photo with prioritised lookup fallbacks
app.get('/api/photos/:imageNo', (req, res) => {
    const imageNo = req.params.imageNo;
    const adm = req.query.adm || '';
    const name = req.query.name || '';
    const emis = req.query.emis || '';
    
    const defaultAvatar = path.join(assetsDir, 'default-avatar.svg');
    
    try {
        if (fs.existsSync(photoDir)) {
            const files = fs.readdirSync(photoDir);
            
            // 1. Admission Number (exact filename match with common extensions)
            if (adm) {
                const extensions = ['.jpg', '.jpeg', '.png'];
                for (let ext of extensions) {
                    const matchedFile = files.find(f => f.toLowerCase() === (adm.toLowerCase() + ext));
                    if (matchedFile) {
                        return res.sendFile(path.join(photoDir, matchedFile));
                    }
                }
            }

            // 2. Student ID (imageNo)
            if (imageNo && imageNo !== '-' && imageNo.toLowerCase() !== 'ab' && imageNo !== 'default') {
                const matchedFile = files.find(f => path.parse(f).name.toLowerCase() === imageNo.toLowerCase());
                if (matchedFile) {
                    return res.sendFile(path.join(photoDir, matchedFile));
                }
            }

            // 3. EMIS Number
            if (emis) {
                const matchedFile = files.find(f => path.parse(f).name.toLowerCase() === emis.toLowerCase());
                if (matchedFile) {
                    return res.sendFile(path.join(photoDir, matchedFile));
                }
            }

            // 4. Student Name
            if (name) {
                const matchedFile = files.find(f => path.parse(f).name.toLowerCase() === name.toLowerCase());
                if (matchedFile) {
                    return res.sendFile(path.join(photoDir, matchedFile));
                }
            }
        }
    } catch (err) {
        console.error("Error serving student photo:", err);
    }
    
    // Fallback to default avatar
    if (fs.existsSync(defaultAvatar)) {
        return res.sendFile(defaultAvatar);
    }
    res.status(404).send('Photo not found');
});

// API: Get certificate history
app.get('/api/certificates', (req, res) => {
    const certs = loadJson(certsFile, []);
    res.json(certs);
});

// API: Generate new certificate
app.post('/api/certificates', (req, res) => {
    const settings = loadJson(settingsFile, defaultSettings);
    const certs = loadJson(certsFile, []);
    
    const { admissionNo, studentName, fatherName, dob, grade, purpose, printedBy } = req.body;
    
    if (!admissionNo || !studentName) {
        return res.status(400).json({ success: false, message: "Missing required student details." });
    }
    
    // Auto-generate certificate number
    const counterStr = String(settings.certificateCounter).padStart(6, '0');
    const certificateNo = `${settings.certificatePrefix}${counterStr}`;
    
    // Update settings counter
    settings.certificateCounter += 1;
    saveJson(settingsFile, settings);
    
    // Create new certificate record
    const newCert = {
        id: Date.now().toString(),
        certificateNo,
        admissionNo,
        studentName,
        fatherName,
        dob,
        grade,
        purpose,
        issueDate: new Date().toLocaleDateString('en-GB'), // DD/MM/YYYY format
        printedBy: printedBy || 'Office Staff',
        status: 'Active'
    };
    
    certs.push(newCert);
    if (saveJson(certsFile, certs)) {
        res.json({ success: true, certificate: newCert });
    } else {
        res.status(500).json({ success: false, message: "Failed to save certificate record." });
    }
});

// API: Cancel certificate
app.post('/api/certificates/cancel/:id', (req, res) => {
    const certs = loadJson(certsFile, []);
    const id = req.params.id;
    const certIdx = certs.findIndex(c => c.id === id);
    
    if (certIdx === -1) {
        return res.status(404).json({ success: false, message: "Certificate record not found." });
    }
    
    certs[certIdx].status = 'Cancelled';
    if (saveJson(certsFile, certs)) {
        res.json({ success: true, certificate: certs[certIdx] });
    } else {
        res.status(500).json({ success: false, message: "Failed to cancel certificate." });
    }
});

// API: Delete certificate (Admin only)
app.delete('/api/certificates/:id', (req, res) => {
    const certs = loadJson(certsFile, []);
    const id = req.params.id;
    const updatedCerts = certs.filter(c => c.id !== id);
    
    if (certs.length === updatedCerts.length) {
        return res.status(404).json({ success: false, message: "Certificate record not found." });
    }
    
    if (saveJson(certsFile, updatedCerts)) {
        res.json({ success: true, message: "Certificate record deleted." });
    } else {
        res.status(500).json({ success: false, message: "Failed to delete certificate." });
    }
});

// API: Generate QR Code data URL
app.get('/api/qrcode', async (req, res) => {
    const text = req.query.text || '';
    if (!text) {
        return res.status(400).send('Missing query text parameter');
    }
    try {
        const qrDataUrl = await QRCode.toDataURL(text, { width: 120, margin: 1 });
        res.json({ qrDataUrl });
    } catch (err) {
        res.status(500).send('Error generating QR code');
    }
});

// Helper: save base64 image data to file
function saveBase64Image(filePath, base64Data) {
    try {
        const matches = base64Data.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/);
        if (!matches || matches.length !== 3) {
            return false;
        }
        const buffer = Buffer.from(matches[2], 'base64');
        const dir = path.dirname(filePath);
        if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
        fs.writeFileSync(filePath, buffer);
        return true;
    } catch (err) {
        console.error(`Error saving base64 image to ${filePath}:`, err);
        return false;
    }
}

// API: Upload Student Photo
app.post('/api/upload/student-photo', (req, res) => {
    const { admissionNo, imageData } = req.body;
    if (!admissionNo || !imageData) {
        return res.status(400).json({ success: false, message: "Missing required parameters." });
    }
    
    const filePath = path.join(photoDir, `${admissionNo}.jpg`);
    if (saveBase64Image(filePath, imageData)) {
        res.json({ success: true, url: `/api/photos/default?adm=${admissionNo}` });
    } else {
        res.status(500).json({ success: false, message: "Failed to save student photo." });
    }
});

// API: Upload Graphic Asset (logo, signature, seal)
app.post('/api/upload/asset', (req, res) => {
    const { assetType, imageData } = req.body;
    if (!assetType || !imageData) {
        return res.status(400).json({ success: false, message: "Missing required parameters." });
    }
    
    let filePath = '';
    let backupPath = '';
    
    if (assetType === 'logo') {
        filePath = path.join(assetsDir, 'logo.png');
        backupPath = defaultLogoSrc;
    } else if (assetType === 'signature') {
        filePath = path.join(assetsDir, 'signature.png');
        backupPath = defaultSignSrc;
    } else if (assetType === 'seal') {
        filePath = path.join(assetsDir, 'seal.png');
    } else {
        return res.status(400).json({ success: false, message: "Invalid asset type." });
    }
    
    if (saveBase64Image(filePath, imageData)) {
        if (backupPath) {
            try {
                const backupDir = path.dirname(backupPath);
                if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true });
                fs.copyFileSync(filePath, backupPath);
            } catch (err) {
                console.error("Backup failed but local asset saved:", err);
            }
        }
        res.json({ success: true });
    } else {
        res.status(500).json({ success: false, message: `Failed to save ${assetType}.` });
    }
});

// API: Delete Graphic Asset
app.delete('/api/assets/:assetType', (req, res) => {
    const assetType = req.params.assetType;
    let filePath = '';
    let backupPath = '';
    
    if (assetType === 'logo') {
        filePath = path.join(assetsDir, 'logo.png');
        backupPath = defaultLogoSrc;
    } else if (assetType === 'signature') {
        filePath = path.join(assetsDir, 'signature.png');
        backupPath = defaultSignSrc;
    } else if (assetType === 'seal') {
        filePath = path.join(assetsDir, 'seal.png');
    } else {
        return res.status(400).json({ success: false, message: "Invalid asset type." });
    }
    
    try {
        if (fs.existsSync(filePath)) {
            fs.unlinkSync(filePath);
        }
        if (backupPath && fs.existsSync(backupPath)) {
            fs.unlinkSync(backupPath);
        }
        res.json({ success: true });
    } catch (err) {
        console.error(`Error deleting asset ${assetType}:`, err);
        res.status(500).json({ success: false, message: `Failed to delete ${assetType} file.` });
    }
});

// Start Server
app.listen(PORT, () => {
    console.log(`Server running at http://localhost:${PORT}`);
});
