/**
 * Test Helper Functions for API Tests with Authentication
 * Provides utilities for cookie extraction and API request handling
 */

const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');

/**
 * Extract cookies from Puppeteer page and format for curl
 * @param {Page} page - Puppeteer page object
 * @returns {string} Cookie string formatted for curl -H "Cookie: ..."
 */
async function getCookieStringFromPage(page) {
    const cookies = await page.cookies();
    return cookies.map(cookie => `${cookie.name}=${cookie.value}`).join('; ');
}

/**
 * Save cookies to file in Netscape format for curl
 * @param {Page} page - Puppeteer page object
 * @param {string} filename - Path to save cookie jar
 */
async function saveCookieJar(page, filename) {
    const cookies = await page.cookies();
    let cookieJar = '# Netscape HTTP Cookie File\n';
    cookieJar += '# This file was generated by test_helpers.js\n\n';

    cookies.forEach(cookie => {
        const httpOnly = cookie.httpOnly ? 'TRUE' : 'FALSE';
        const secure = cookie.secure ? 'TRUE' : 'FALSE';
        const expiry = cookie.expires || 0;

        cookieJar += [
            cookie.domain,
            'TRUE', // include subdomains
            cookie.path,
            secure,
            Math.floor(expiry),
            cookie.name,
            cookie.value
        ].join('\t') + '\n';
    });

    fs.writeFileSync(filename, cookieJar);
}

/**
 * Execute curl command and return parsed response
 * @param {string} command - Curl command to execute
 * @returns {Object} { status, headers, body, error }
 */
function executeCurl(command) {
    try {
        // Add -i to include headers and -s for silent mode
        const fullCommand = command.includes('-i') ? command : command.replace('curl', 'curl -i -s');
        const output = execSync(fullCommand, { encoding: 'utf8' });

        // Parse HTTP response
        const lines = output.split('\n');
        let statusLine = '';
        const headers = {};
        let bodyStartIndex = 0;

        // Find status line
        for (let i = 0; i < lines.length; i++) {
            if (lines[i].startsWith('HTTP/')) {
                statusLine = lines[i];
                bodyStartIndex = i + 1;
                break;
            }
        }

        // Parse headers
        for (let i = bodyStartIndex; i < lines.length; i++) {
            if (lines[i].trim() === '') {
                bodyStartIndex = i + 1;
                break;
            }
            const colonIndex = lines[i].indexOf(':');
            if (colonIndex > -1) {
                const key = lines[i].substring(0, colonIndex).trim().toLowerCase();
                const value = lines[i].substring(colonIndex + 1).trim();
                headers[key] = value;
            }
        }

        // Get body
        const body = lines.slice(bodyStartIndex).join('\n').trim();

        // Extract status code
        const statusMatch = statusLine.match(/HTTP\/[\d.]+ (\d+)/);
        const status = statusMatch ? parseInt(statusMatch[1], 10) : 0;

        return {
            status,
            headers,
            body: tryParseJSON(body),
            raw: output
        };
    } catch (error) {
        return {
            error: error.message,
            command
        };
    }
}

/**
 * Try to parse JSON, return original string if fails
 */
function tryParseJSON(str) {
    try {
        return JSON.parse(str);
    } catch {
        return str;
    }
}

/**
 * Make authenticated API request using curl
 * @param {string} url - Full URL to request
 * @param {string} cookieString - Cookie string from getCookieStringFromPage
 * @param {Object} options - Additional curl options
 * @returns {Object} Response object
 */
function makeAuthenticatedRequest(url, cookieString, options = {}) {
    const method = options.method || 'GET';
    const headers = options.headers || {};

    let command = `curl -X ${method} "${url}"`;

    // Add cookie header
    if (cookieString) {
        command += ` -H "Cookie: ${cookieString}"`;
    }

    // Add other headers
    Object.entries(headers).forEach(([key, value]) => {
        command += ` -H "${key}: ${value}"`;
    });

    // Add data for POST/PUT
    if (options.data) {
        if (typeof options.data === 'object') {
            command += ` -d '${JSON.stringify(options.data)}'`;
            command += ` -H "Content-Type: application/json"`;
        } else {
            command += ` -d '${options.data}'`;
        }
    }

    return executeCurl(command);
}

module.exports = {
    getCookieStringFromPage,
    saveCookieJar,
    executeCurl,
    makeAuthenticatedRequest,
    tryParseJSON
};
