// @ts-check
import { existsSync, readFileSync } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { captureLogMessage, patchConsoleLogs } from '../common/logger.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);


/**
 * write logs to local file
 * @param {string} command
 * @param {unknown} _config
 * @param {import('../types/userconfig.js').userSettings} userSettings
 * @returns {import('vite').Plugin | null}
 */
export function needleLogger(command, _config, userSettings) {

    if (userSettings?.disableLogging === true) {
        return null;
    }

    patchConsoleLogs({ command });
    captureLogMessage("server", "info", "Vite started with command \"" + command + "\" in " + __dirname, null);

    return {
        name: "needle:logger",
        enforce: 'pre',
        configureServer(server) {
            logRequests(server);
        },
        configurePreviewServer(server) {
            logRequests(server);
        },
        transformIndexHtml: {
            order: 'pre',
            handler(_html, _ctx) {
                // inject client logger script during development
                if (command === 'serve') {
                    const file = path.join(__dirname, 'logger.client.js');
                    if (existsSync(file)) {
                        const scriptContent = readFileSync(file, 'utf8');
                        return [
                            {
                                tag: 'script',
                                attrs: {
                                    type: 'module',
                                },
                                children: scriptContent,
                                injectTo: 'head-prepend',
                            },
                        ];
                    }
                }
                return [];
            },
        }
    }
}


/**
 * Logs HTTP requests to the console.
 * This function is used in the Vite server to log incoming HTTP requests.
 * @param {import('vite').PreviewServer | import('vite').ViteDevServer} server
 */
function logRequests(server, log_http_requests = false) {
    /**
     * Logs a message to the server console and captures it.
     * @type {Map<import("vite").WebSocket, {id:string}>}
     */
    const connectedClients = new Map();
    let index = 0;

    if ("ws" in server) {
        // Clent connections
        server.ws.on('connection', (socket, request) => {
            const clientId = String(index++);
            connectedClients.set(socket, { id: clientId });
            const ip = request.socket.remoteAddress || 'unknown';
            captureLogMessage("server", "connection", `New websocket connection established ${clientId} from ${ip}`, clientId);
            socket.on('close', () => {
                captureLogMessage("server", "connection", `Websocket connection closed ${clientId}`, clientId);
            });
        });
        // Client log messages via websocket
        server.ws.on('needle:client-log', async (/** @type {{level: string, message: unknown}} */ data, /** @type {import('vite').WebSocketClient} */ client) => {
            if (!data || !data.level || !data.message) {
                console.warn("Received empty log data, ignoring");
                return;
            }
            const info = connectedClients.get(client.socket);
            captureLogMessage("client", data.level, data.message, info ? info.id : null);
        });
    }
    // Log HTTP requests
    server.middlewares.use((req, _res, next) => {
        if (log_http_requests) {
            captureLogMessage("client-http", "info", [req.method, req.url], null);
        }
        next();
    });
}