import fs from 'node:fs/promises';
import path from 'node:path';
import { compiledContentRoot } from '../content/routes.js';
import { DEFAULT_DEV_REFRESH_PATH, DEFAULT_DEV_REFRESH_PORT, } from './browser.js';
export { DEFAULT_DEV_REFRESH_PATH, DEFAULT_DEV_REFRESH_PORT } from './browser.js';
function numberOption(value, fallback) {
    if (value === undefined || value === '') {
        return fallback;
    }
    const parsed = Number(value);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}
export function devRefreshPort(options = {}) {
    const value = options.wsPort ?? process.env.ACI_DEV_WS_PORT;
    if (value === 0 || value === '0') {
        return 0;
    }
    return numberOption(value, DEFAULT_DEV_REFRESH_PORT);
}
export function devRefreshScript(options = {}) {
    const wsPort = devRefreshPort(options);
    if (wsPort <= 0) {
        return '';
    }
    const wsPath = options.path || DEFAULT_DEV_REFRESH_PATH;
    const reconnectMs = numberOption(options.reconnectMs, 1000);
    return `(() => {
  if (typeof window === 'undefined' || window.__gradialDevRefresh) return;
  window.__gradialDevRefresh = true;
  const port = ${JSON.stringify(wsPort)};
  const path = ${JSON.stringify(wsPath)};
  const reconnectMs = ${JSON.stringify(reconnectMs)};
  const connect = () => {
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const socket = new WebSocket(protocol + '//' + window.location.hostname + ':' + port + path);
    socket.addEventListener('message', (event) => {
      try {
        const message = JSON.parse(event.data);
        if (message && message.type === 'content-updated') window.location.reload();
      } catch (_) {
      }
    });
    socket.addEventListener('close', () => window.setTimeout(connect, reconnectMs));
  };
  connect();
})();`;
}
export function devRefreshScriptTag(options = {}) {
    return `<script>${devRefreshScript(options)}</script>`;
}
export function gradialContentWatchPlugin(options = {}) {
    const enabled = options.enabled ?? process.env.ACI_DISABLE_CONTENT_WATCH !== '1';
    return {
        name: 'gradial-content-watch',
        apply: 'serve',
        configureServer(server) {
            if (!enabled) {
                return;
            }
            const root = path.resolve(options.contentRoot || compiledContentRoot());
            server.watcher.add(root);
            server.watcher.on('all', (_eventName, filePath) => {
                const changed = path.resolve(filePath);
                const relative = path.relative(root, changed);
                if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) {
                    server.ws.send({ type: 'full-reload', path: '*' });
                }
            });
        },
    };
}
export function gradialDamAssetPlugin(options = {}) {
    return {
        name: 'gradial-dam-assets',
        apply: 'serve',
        configureServer(server) {
            if (!server.middlewares) {
                return;
            }
            server.middlewares.use('/.gradial-dam', async (req, res, next) => {
                const root = path.resolve(options.compiledRoot || compiledContentRoot());
                const requestPath = safeRequestPath(req.url || '');
                if (!requestPath) {
                    res.statusCode = 404;
                    res.end('asset not found');
                    return;
                }
                const filePath = path.resolve(root, '.gradial-dam', requestPath.replace(/^\/+/, ''));
                if (!isInside(root, filePath)) {
                    res.statusCode = 404;
                    res.end('asset not found');
                    return;
                }
                try {
                    const body = await fs.readFile(filePath);
                    res.statusCode = 200;
                    res.setHeader('Content-Type', contentType(filePath));
                    res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
                    res.end(body);
                }
                catch {
                    next();
                }
            });
        },
    };
}
function safeRequestPath(url) {
    const rawPath = url.split('?')[0] || '';
    try {
        const decoded = decodeURIComponent(rawPath);
        return decoded.startsWith('/.gradial-dam/') ? decoded.slice('/.gradial-dam/'.length) : decoded;
    }
    catch {
        return '';
    }
}
function isInside(root, filePath) {
    const rel = path.relative(root, filePath);
    return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);
}
function contentType(filePath) {
    switch (path.extname(filePath).toLowerCase()) {
        case '.webp':
            return 'image/webp';
        case '.svg':
            return 'image/svg+xml';
        case '.jpg':
        case '.jpeg':
            return 'image/jpeg';
        case '.png':
            return 'image/png';
        default:
            return 'application/octet-stream';
    }
}
