// Feedback route — proxies bug reports and feature requests to GitLab Issues API
// Supports optional screenshot uploads (up to 3 images, 5MB each).
// Keeps the GitLab PAT server-side so it's never exposed to the browser.

const express = require('express');
const https = require('https');
const http = require('http');
const path = require('path');
const fs = require('fs');
const multer = require('multer');
const { requireAuth } = require('../middleware/auth');

// Multer setup for screenshot uploads — same temp directory pattern as compliance
const TEMP_DIR = path.join(process.cwd(), 'uploads', 'temp');

const screenshotStorage = multer.diskStorage({
    destination: (req, file, cb) => {
        if (!fs.existsSync(TEMP_DIR)) {
            fs.mkdirSync(TEMP_DIR, { recursive: true });
        }
        cb(null, TEMP_DIR);
    },
    filename: (req, file, cb) => {
        const timestamp = Date.now();
        const safeName = file.originalname
            .replace(/\0/g, '')
            .replace(/\.\./g, '')
            .replace(/[\/\\]/g, '')
            .replace(/[^a-zA-Z0-9._-]/g, '_')
            .trim();
        cb(null, `${timestamp}-${safeName}`);
    },
});

const ALLOWED_IMAGE_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB

const screenshotUpload = multer({
    storage: screenshotStorage,
    fileFilter: (req, file, cb) => {
        if (!ALLOWED_IMAGE_TYPES.has(file.mimetype)) {
            return cb(new Error(`File type '${file.mimetype}' not allowed. Only PNG, JPG, GIF, and WebP images are accepted.`));
        }
        cb(null, true);
    },
    limits: {
        fileSize: MAX_FILE_SIZE,
        files: 3,
    },
});

function createFeedbackRouter() {
    const router = express.Router();

    const GITLAB_URL = process.env.GITLAB_URL || '';
    const GITLAB_PROJECT_ID = process.env.GITLAB_PROJECT_ID || '';
    const GITLAB_PAT = process.env.GITLAB_PAT || '';

    /**
     * Upload a single file to GitLab's project uploads API.
     * Returns { markdown, url } on success, null on failure.
     */
    function uploadFileToGitlab(filePath, fileName) {
        return new Promise((resolve) => {
            const apiUrl = `${GITLAB_URL.replace(/\/$/, '')}/api/v4/projects/${encodeURIComponent(GITLAB_PROJECT_ID)}/uploads`;

            try {
                const parsed = new URL(apiUrl);
                const transport = parsed.protocol === 'https:' ? https : http;

                const boundary = `----FormBoundary${Date.now()}${Math.random().toString(36).slice(2)}`;
                const fileContent = fs.readFileSync(filePath);

                const header = Buffer.from(
                    `--${boundary}\r\n` +
                    `Content-Disposition: form-data; name="file"; filename="${fileName}"\r\n` +
                    `Content-Type: application/octet-stream\r\n\r\n`
                );
                const footer = Buffer.from(`\r\n--${boundary}--\r\n`);
                const body = Buffer.concat([header, fileContent, footer]);

                const reqOpts = {
                    method: 'POST',
                    hostname: parsed.hostname,
                    port: parsed.port,
                    path: parsed.pathname + parsed.search,
                    headers: {
                        'Content-Type': `multipart/form-data; boundary=${boundary}`,
                        'PRIVATE-TOKEN': GITLAB_PAT,
                        'Content-Length': body.length,
                    },
                    rejectAuthorized: false,
                };

                const apiReq = transport.request(reqOpts, (apiRes) => {
                    let data = '';
                    apiRes.on('data', chunk => data += chunk);
                    apiRes.on('end', () => {
                        try {
                            const result = JSON.parse(data);
                            if (apiRes.statusCode === 201 && result.markdown) {
                                resolve(result);
                            } else {
                                console.error(`[Feedback] GitLab upload returned ${apiRes.statusCode}:`, data);
                                resolve(null);
                            }
                        } catch {
                            console.error('[Feedback] GitLab upload returned invalid JSON:', data);
                            resolve(null);
                        }
                    });
                });

                apiReq.on('error', (err) => {
                    console.error('[Feedback] GitLab upload request error:', err.message);
                    resolve(null);
                });

                apiReq.write(body);
                apiReq.end();
            } catch (err) {
                console.error('[Feedback] GitLab upload error:', err.message);
                resolve(null);
            }
        });
    }

    /**
     * Clean up temp files after processing.
     */
    function cleanupFiles(files) {
        for (const file of files) {
            try {
                if (fs.existsSync(file.path)) {
                    fs.unlinkSync(file.path);
                }
            } catch (err) {
                console.error(`[Feedback] Failed to clean up temp file ${file.path}:`, err.message);
            }
        }
    }

    router.post('/', requireAuth(), screenshotUpload.array('screenshots', 3), async (req, res) => {
        const uploadedFiles = req.files || [];

        try {
            if (!GITLAB_URL || !GITLAB_PROJECT_ID || !GITLAB_PAT) {
                return res.status(503).json({ error: 'Feedback integration not configured' });
            }

            const { type, title, description, page } = req.body;

            if (!type || !title || !description) {
                return res.status(400).json({ error: 'type, title, and description are required' });
            }

            if (!['bug', 'feature'].includes(type)) {
                return res.status(400).json({ error: 'type must be "bug" or "feature"' });
            }

            const labels = type === 'bug' ? 'bug' : 'enhancement';
            const prefix = type === 'bug' ? '🐛 Bug' : '✨ Feature Request';
            const username = req.user?.username || 'unknown';

            // Upload screenshots to GitLab and collect markdown links
            const imageMarkdowns = [];
            for (const file of uploadedFiles) {
                const result = await uploadFileToGitlab(file.path, file.originalname);
                if (result && result.markdown) {
                    imageMarkdowns.push(result.markdown);
                }
            }

            const bodyParts = [
                `**Submitted by:** ${username}`,
                page ? `**Page:** ${page}` : null,
                `**Type:** ${prefix}`,
                '',
                '---',
                '',
                description,
            ].filter(Boolean);

            // Append screenshot markdown at the bottom
            if (imageMarkdowns.length > 0) {
                bodyParts.push('');
                bodyParts.push('---');
                bodyParts.push('');
                bodyParts.push('**Screenshots:**');
                bodyParts.push('');
                for (const md of imageMarkdowns) {
                    bodyParts.push(md);
                    bodyParts.push('');
                }
            }

            const body = bodyParts.join('\n');

            const postData = JSON.stringify({
                title: `[${prefix}] ${title}`,
                description: body,
                labels,
            });

            const apiUrl = `${GITLAB_URL.replace(/\/$/, '')}/api/v4/projects/${encodeURIComponent(GITLAB_PROJECT_ID)}/issues`;

            const result = await new Promise((resolve, reject) => {
                const parsed = new URL(apiUrl);
                const transport = parsed.protocol === 'https:' ? https : http;

                const reqOpts = {
                    method: 'POST',
                    hostname: parsed.hostname,
                    port: parsed.port,
                    path: parsed.pathname + parsed.search,
                    headers: {
                        'Content-Type': 'application/json',
                        'PRIVATE-TOKEN': GITLAB_PAT,
                        'Content-Length': Buffer.byteLength(postData),
                    },
                    rejectAuthorized: false,
                };

                const apiReq = transport.request(reqOpts, (apiRes) => {
                    let data = '';
                    apiRes.on('data', chunk => data += chunk);
                    apiRes.on('end', () => {
                        try {
                            resolve({ status: apiRes.statusCode, body: JSON.parse(data) });
                        } catch {
                            resolve({ status: apiRes.statusCode, body: data });
                        }
                    });
                });

                apiReq.on('error', reject);
                apiReq.write(postData);
                apiReq.end();
            });

            if (result.status === 201) {
                console.log(`[Feedback] Issue #${result.body.iid} created by ${username}: ${title}`);
                res.json({
                    success: true,
                    issue: {
                        id: result.body.iid,
                        url: result.body.web_url,
                        title: result.body.title,
                    },
                });
            } else {
                console.error(`[Feedback] GitLab API returned ${result.status}:`, result.body);
                res.status(502).json({ error: 'GitLab API error', details: result.body });
            }
        } catch (err) {
            console.error('[Feedback] Request failed:', err.message);
            res.status(502).json({ error: 'Failed to connect to GitLab' });
        } finally {
            // Always clean up temp files
            cleanupFiles(uploadedFiles);
        }
    });

    return router;
}

module.exports = createFeedbackRouter;
