import picocolors from 'picocolors';

const { createColors, isColorSupported } = picocolors;

const colors = createColors(isColorSupported);
/** @type {null | (() => void)} */
let transientLogLineCleaner = null;

/**
 * Tracks the last plugin name that called needleLog.
 * Used to suppress repeated header lines for consecutive logs from the same plugin.
 * @type {string | null}
 */
let lastLoggedPlugin = null;

/**
 * Resets the sticky-header state so the next needleLog call always emits its
 * [plugin-name] header. Call this at the start of a new build or any logical
 * output section where you want a guaranteed fresh header.
 */
export function resetLastLoggedPlugin() {
    lastLoggedPlugin = null;
}

function getConsoleMethod(level) {
    if (level === 'error') return console.error;
    if (level === 'warn') return console.warn;
    return console.log;
}

function colorBodyByLevel(level, text) {
    if (!isColorSupported) return text;
    if (level === 'error') return colors.red(text);
    if (level === 'warn') return colors.yellow(text);
    return text;
}

function normalizeMessage(message) {
    if (Array.isArray(message)) return message.join("\n");
    if (message === undefined || message === null) return "";
    return String(message);
}

function formatHeader(pluginName) {
    if (!isColorSupported) return `[${pluginName}]`;

    const name = String(pluginName ?? "");
    let prefix = "";
    let suffix = name;
    if (name.startsWith("needle-")) {
        prefix = "needle-";
        suffix = name.substring("needle-".length);
    }
    else if (name.startsWith("needle:")) {
        prefix = "needle:";
        suffix = name.substring("needle:".length);
    }

    const open = colors.green("[");
    const close = colors.green("]");
    if (!prefix.length) {
        return `${open}${colors.bold(colors.green(name))}${close}`;
    }
    const prefixStyled = colors.green(prefix);
    const suffixStyled = colors.bold(colors.green(suffix));
    return `${open}${prefixStyled}${suffixStyled}${close}`;
}

/**
 * @param {string} pluginName
 * @param {string | string[]} message
 * @param {'log' | 'warn' | 'error'} [level='log']
 * @param {{ dimBody?: boolean, leadingNewline?: boolean, showHeader?: boolean }} [options]
 */
export function needleLog(pluginName, message, level = 'log', options = undefined) {
    if (typeof transientLogLineCleaner === "function") {
        transientLogLineCleaner();
    }
    const log = getConsoleMethod(level);
    const headerText = formatHeader(pluginName);
    const bodyText = normalizeMessage(message);
    const dimBody = options?.dimBody ?? (level === 'log');
    const leadingNewline = options?.leadingNewline === true;
    const showHeader = options?.showHeader !== false;

    // Sticky header: only re-emit [plugin-name] when the plugin changes.
    // Always re-emit for warn/error (for clarity), header-only calls (no body),
    // or section breaks (leadingNewline).
    const pluginChanged = pluginName !== lastLoggedPlugin;
    const emitHeader = showHeader && (pluginChanged || level !== 'log' || bodyText.length === 0 || leadingNewline);
    lastLoggedPlugin = pluginName;

    if (isColorSupported) {
        const header = `\x1b[0m${headerText}`;
        const leveledBody = colorBodyByLevel(level, bodyText);
        const body = bodyText.length > 0
            ? (dimBody ? leveledBody.split('\n').map(l => colors.dim(l)).join('\n') : leveledBody)
            : "";
        const payloadCore = emitHeader
            ? (body.length > 0 ? `${header}\n${body}\n` : `${header}\n`)
            : (body.length > 0 ? `${body}\n` : "");
        const payload = leadingNewline ? `\n${payloadCore}` : payloadCore;
        log(payload);
        return;
    }

    if (bodyText.length > 0) {
        const out = emitHeader ? `${headerText} ${bodyText}` : bodyText;
        log(leadingNewline ? `\n${out}` : out);
    }
    else {
        const out = emitHeader ? headerText : "";
        if (out.length > 0) {
            log(leadingNewline ? `\n${out}` : out);
        }
    }
}

/**
 * @param {string} pluginName
 * @param {string[]} lines
 * @param {'log' | 'warn' | 'error'} [level='log']
 */
export function needleLogLines(pluginName, lines, level = 'log') {
    needleLog(pluginName, lines.join("\n"), level);
}

export function needleSupportsColor() {
    return isColorSupported;
}

export function needleBlue(text) {
    const value = String(text ?? "");
    return isColorSupported ? colors.blue(value) : value;
}

export function needleDim(text) {
    const value = String(text ?? "");
    return isColorSupported ? colors.dim(value) : value;
}

export function needleGreenBold(text) {
    const value = String(text ?? "");
    return isColorSupported ? colors.bold(colors.green(value)) : value;
}

/**
 * @param {(() => void) | null} cleaner
 */
export function setTransientLogLineCleaner(cleaner) {
    transientLogLineCleaner = typeof cleaner === "function" ? cleaner : null;
}
