const http = require('http');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

// Configuration
const UPLOAD_PASSWORD = process.env.UPLOAD_PASSWORD || 'rosy-photo-2024';
const UPLOAD_DIR = '/uploads';
const PORT = 3000;
const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB

// Allowed image extensions
const ALLOWED_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];

function parseMultipart(buffer, boundary) {
    const parts = [];
    const boundaryBuffer = Buffer.from('--' + boundary);

    let start = buffer.indexOf(boundaryBuffer);
    while (start !== -1) {
        const end = buffer.indexOf(boundaryBuffer, start + boundaryBuffer.length);
        if (end === -1) break;

        const part = buffer.slice(start + boundaryBuffer.length, end);
        const headerEnd = part.indexOf('\r\n\r\n');
        if (headerEnd !== -1) {
            const headers = part.slice(0, headerEnd).toString();
            const content = part.slice(headerEnd + 4, part.length - 2); // Remove trailing \r\n

            const nameMatch = headers.match(/name="([^"]+)"/);
            const filenameMatch = headers.match(/filename="([^"]+)"/);

            if (nameMatch) {
                parts.push({
                    name: nameMatch[1],
                    filename: filenameMatch ? filenameMatch[1] : null,
                    data: content
                });
            }
        }
        start = end;
    }
    return parts;
}

function sanitizeFilename(filename) {
    // Remove path components and sanitize
    const base = path.basename(filename);
    // Replace spaces and special chars with underscores
    return base.replace(/[^a-zA-Z0-9._-]/g, '_').toLowerCase();
}

function generateUniqueFilename(originalName) {
    const ext = path.extname(originalName).toLowerCase();
    const base = path.basename(originalName, ext);
    const timestamp = Date.now();
    const random = crypto.randomBytes(4).toString('hex');
    return `${sanitizeFilename(base)}_${timestamp}_${random}${ext}`;
}

const server = http.createServer((req, res) => {
    // Log all requests
    console.log(`${req.method} ${req.url}`);

    // CORS headers
    res.setHeader('Access-Control-Allow-Origin', 'https://rosy.shitchell.com');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

    if (req.method === 'OPTIONS') {
        res.writeHead(200);
        res.end();
        return;
    }

    // GET /photos - list all photos
    if (req.method === 'GET' && req.url === '/photos') {
        try {
            const photos = { landscapes: [], historic: [] };

            // Load metadata
            const metadataPath = path.join(UPLOAD_DIR, 'metadata.json');
            let metadata = {};
            if (fs.existsSync(metadataPath)) {
                try {
                    metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
                } catch (e) {
                    metadata = {};
                }
            }

            for (const category of ['landscapes', 'historic']) {
                const dir = path.join(UPLOAD_DIR, category);
                if (fs.existsSync(dir)) {
                    const files = fs.readdirSync(dir)
                        .filter(f => ALLOWED_EXTENSIONS.includes(path.extname(f).toLowerCase()))
                        .map(filename => {
                            const filePath = path.join(dir, filename);
                            const stats = fs.statSync(filePath);
                            const meta = metadata[filename] || {};
                            return {
                                filename,
                                title: meta.title || '',
                                path: `/photography/uploads/${category}/${filename}`,
                                category,
                                uploaded: meta.uploaded || stats.mtime.toISOString(),
                                sortOrder: meta.sortOrder !== undefined ? meta.sortOrder : 9999
                            };
                        })
                        // Sort by sortOrder first, then by upload date (newest first) as tiebreaker
                        .sort((a, b) => {
                            if (a.sortOrder !== b.sortOrder) {
                                return a.sortOrder - b.sortOrder;
                            }
                            return new Date(b.uploaded) - new Date(a.uploaded);
                        });

                    photos[category] = files;
                }
            }

            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(photos));
            return;
        } catch (err) {
            console.error('List photos error:', err);
            res.writeHead(500, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: 'Server error' }));
            return;
        }
    }

    // POST /edit - edit photo title
    if (req.method === 'POST' && req.url === '/edit') {
        let body = '';
        req.on('data', chunk => body += chunk);
        req.on('end', () => {
            try {
                const { filename, category, title, password } = JSON.parse(body);

                if (password !== UPLOAD_PASSWORD) {
                    res.writeHead(401, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Invalid password' }));
                    return;
                }

                const metadataPath = path.join(UPLOAD_DIR, 'metadata.json');
                let metadata = {};
                if (fs.existsSync(metadataPath)) {
                    metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
                }

                if (metadata[filename]) {
                    metadata[filename].title = title;
                } else {
                    metadata[filename] = { title, category, uploaded: new Date().toISOString() };
                }
                fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));

                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ success: true }));
            } catch (err) {
                console.error('Edit error:', err);
                res.writeHead(500, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Server error' }));
            }
        });
        return;
    }

    // POST /reorder - reorder photos in a category
    if (req.method === 'POST' && req.url === '/reorder') {
        let body = '';
        req.on('data', chunk => body += chunk);
        req.on('end', () => {
            try {
                const { category, order, password } = JSON.parse(body);

                if (password !== UPLOAD_PASSWORD) {
                    res.writeHead(401, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Invalid password' }));
                    return;
                }

                if (!category || !Array.isArray(order)) {
                    res.writeHead(400, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Missing category or order array' }));
                    return;
                }

                const metadataPath = path.join(UPLOAD_DIR, 'metadata.json');
                let metadata = {};
                if (fs.existsSync(metadataPath)) {
                    metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
                }

                // Update sortOrder for each filename in the order array
                order.forEach((filename, index) => {
                    if (metadata[filename]) {
                        metadata[filename].sortOrder = index;
                    } else {
                        metadata[filename] = { sortOrder: index, category };
                    }
                });

                fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));

                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ success: true }));
            } catch (err) {
                console.error('Reorder error:', err);
                res.writeHead(500, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Server error' }));
            }
        });
        return;
    }

    // POST /delete - delete photo
    if (req.method === 'POST' && req.url === '/delete') {
        let body = '';
        req.on('data', chunk => body += chunk);
        req.on('end', () => {
            try {
                const { filename, category, password } = JSON.parse(body);

                if (password !== UPLOAD_PASSWORD) {
                    res.writeHead(401, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Invalid password' }));
                    return;
                }

                // Delete file
                const filePath = path.join(UPLOAD_DIR, category, filename);
                if (fs.existsSync(filePath)) {
                    fs.unlinkSync(filePath);
                }

                // Remove from metadata
                const metadataPath = path.join(UPLOAD_DIR, 'metadata.json');
                if (fs.existsSync(metadataPath)) {
                    let metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
                    delete metadata[filename];
                    fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
                }

                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ success: true }));
            } catch (err) {
                console.error('Delete error:', err);
                res.writeHead(500, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Server error' }));
            }
        });
        return;
    }

    // POST /replace - replace photo with a new one (keeps same filename/metadata)
    if (req.method === 'POST' && (req.url === '/replace' || req.url === '/replace/')) {
        console.log('Replace endpoint called, URL:', req.url);
        const contentType = req.headers['content-type'] || '';
        console.log('Content-Type:', contentType);
        if (!contentType.includes('multipart/form-data')) {
            console.log('Invalid content type for replace');
            res.writeHead(400, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: 'Invalid content type' }));
            return;
        }

        const boundary = contentType.split('boundary=')[1];
        if (!boundary) {
            res.writeHead(400, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: 'No boundary found' }));
            return;
        }

        let body = [];
        let size = 0;

        req.on('data', chunk => {
            size += chunk.length;
            if (size > MAX_FILE_SIZE) {
                res.writeHead(413, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'File too large (max 20MB)' }));
                req.destroy();
                return;
            }
            body.push(chunk);
        });

        req.on('end', () => {
            try {
                const buffer = Buffer.concat(body);
                const parts = parseMultipart(buffer, boundary);

                const passwordPart = parts.find(p => p.name === 'password');
                const filenamePart = parts.find(p => p.name === 'filename');
                const categoryPart = parts.find(p => p.name === 'category');
                const filePart = parts.find(p => p.name === 'photo' && p.filename);

                // Check password
                const password = passwordPart ? passwordPart.data.toString().trim() : '';
                if (password !== UPLOAD_PASSWORD) {
                    res.writeHead(401, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Invalid password' }));
                    return;
                }

                // Check required fields
                const oldFilename = filenamePart ? filenamePart.data.toString().trim() : '';
                const category = categoryPart ? categoryPart.data.toString().trim() : '';

                if (!oldFilename || !category) {
                    res.writeHead(400, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Missing filename or category' }));
                    return;
                }

                if (!filePart) {
                    res.writeHead(400, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'No file uploaded' }));
                    return;
                }

                // Check extension
                const ext = path.extname(filePart.filename).toLowerCase();
                if (!ALLOWED_EXTENSIONS.includes(ext)) {
                    res.writeHead(400, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Invalid file type. Allowed: ' + ALLOWED_EXTENSIONS.join(', ') }));
                    return;
                }

                // Verify old file exists
                const oldFilePath = path.join(UPLOAD_DIR, category, oldFilename);
                console.log('Looking for file:', oldFilePath);
                console.log('File exists:', fs.existsSync(oldFilePath));
                if (!fs.existsSync(oldFilePath)) {
                    res.writeHead(404, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Original file not found' }));
                    return;
                }

                // Generate new unique filename
                const newFilename = generateUniqueFilename(filePart.filename);
                const newFilePath = path.join(UPLOAD_DIR, category, newFilename);

                // Write new file
                fs.writeFileSync(newFilePath, filePart.data);

                // Delete old file
                fs.unlinkSync(oldFilePath);

                // Update metadata - transfer old metadata to new filename
                const metadataPath = path.join(UPLOAD_DIR, 'metadata.json');
                let metadata = {};
                if (fs.existsSync(metadataPath)) {
                    try {
                        metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
                    } catch (e) {
                        metadata = {};
                    }
                }

                // Copy old metadata to new filename, update timestamp
                const oldMeta = metadata[oldFilename] || {};
                metadata[newFilename] = {
                    title: oldMeta.title || '',
                    category: category,
                    uploaded: new Date().toISOString()
                };
                delete metadata[oldFilename];
                fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));

                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({
                    success: true,
                    oldFilename: oldFilename,
                    newFilename: newFilename,
                    path: `/photography/uploads/${category}/${newFilename}`
                }));

            } catch (err) {
                console.error('Replace error:', err);
                res.writeHead(500, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Server error' }));
            }
        });
        return;
    }

    if (req.method !== 'POST' || req.url !== '/upload') {
        res.writeHead(404, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'Not found' }));
        return;
    }

    const contentType = req.headers['content-type'] || '';
    if (!contentType.includes('multipart/form-data')) {
        res.writeHead(400, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'Invalid content type' }));
        return;
    }

    const boundary = contentType.split('boundary=')[1];
    if (!boundary) {
        res.writeHead(400, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'No boundary found' }));
        return;
    }

    let body = [];
    let size = 0;

    req.on('data', chunk => {
        size += chunk.length;
        if (size > MAX_FILE_SIZE) {
            res.writeHead(413, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: 'File too large (max 20MB)' }));
            req.destroy();
            return;
        }
        body.push(chunk);
    });

    req.on('end', () => {
        try {
            const buffer = Buffer.concat(body);
            const parts = parseMultipart(buffer, boundary);

            // Find password, title and file
            const passwordPart = parts.find(p => p.name === 'password');
            const categoryPart = parts.find(p => p.name === 'category');
            const titlePart = parts.find(p => p.name === 'title');
            const filePart = parts.find(p => p.name === 'photo' && p.filename);

            // Check password
            const password = passwordPart ? passwordPart.data.toString().trim() : '';
            if (password !== UPLOAD_PASSWORD) {
                res.writeHead(401, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Invalid password' }));
                return;
            }

            // Check file exists
            if (!filePart) {
                res.writeHead(400, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'No file uploaded' }));
                return;
            }

            // Check extension
            const ext = path.extname(filePart.filename).toLowerCase();
            if (!ALLOWED_EXTENSIONS.includes(ext)) {
                res.writeHead(400, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Invalid file type. Allowed: ' + ALLOWED_EXTENSIONS.join(', ') }));
                return;
            }

            // Get category (landscapes or historic)
            const category = categoryPart ? categoryPart.data.toString().trim() : 'landscapes';
            const validCategories = ['landscapes', 'historic'];
            const safeCategory = validCategories.includes(category) ? category : 'landscapes';

            // Get title
            const title = titlePart ? titlePart.data.toString().trim() : '';

            // Generate unique filename and save
            const uniqueFilename = generateUniqueFilename(filePart.filename);
            const savePath = path.join(UPLOAD_DIR, safeCategory, uniqueFilename);

            // Ensure directory exists
            const dir = path.dirname(savePath);
            if (!fs.existsSync(dir)) {
                fs.mkdirSync(dir, { recursive: true });
            }

            fs.writeFileSync(savePath, filePart.data);

            // Save metadata (title) to JSON file
            const metadataPath = path.join(UPLOAD_DIR, 'metadata.json');
            let metadata = {};
            if (fs.existsSync(metadataPath)) {
                try {
                    metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
                } catch (e) {
                    metadata = {};
                }
            }
            metadata[uniqueFilename] = { title, category: safeCategory, uploaded: new Date().toISOString() };
            fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));

            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({
                success: true,
                filename: uniqueFilename,
                title: title,
                category: safeCategory,
                path: `/photography/uploads/${safeCategory}/${uniqueFilename}`
            }));

        } catch (err) {
            console.error('Upload error:', err);
            res.writeHead(500, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: 'Server error' }));
        }
    });
});

server.listen(PORT, '0.0.0.0', () => {
    console.log(`Upload server running on port ${PORT}`);
});
