import MarkdownIt from 'markdown-it';
import markdownItIns from 'markdown-it-ins';
import markdownItMark from 'markdown-it-mark';
import markdownItSub from 'markdown-it-sub';
import markdownItSup from 'markdown-it-sup';
import { readFileSync, existsSync } from 'fs';
import { join, extname } from 'path';
// Lazy-load server modules at runtime
// npm package: dist/plugins/publish/dist/helpers.js → ../../../server/
// Monorepo:    plugins/publish/dist/helpers.js → ../../../packages/openwriter/dist/server/
const npmBase = new URL('../../../server/', import.meta.url).href;
const monoBase = new URL('../../../packages/openwriter/dist/server/', import.meta.url).href;
let _cached = null;
async function tryImport(base) {
    const [markdown, state, helpers, connections] = await Promise.all([
        import(base + 'markdown.js'),
        import(base + 'state.js'),
        import(base + 'helpers.js'),
        import(base + 'connections.js'),
    ]);
    return { markdown, state, helpers, connections };
}
export async function getServerModules() {
    if (_cached)
        return _cached;
    // Try npm package layout first, fall back to monorepo layout
    let markdown, state, helpers, connections;
    try {
        ({ markdown, state, helpers, connections } = await tryImport(npmBase));
    }
    catch {
        ({ markdown, state, helpers, connections } = await tryImport(monoBase));
    }
    _cached = {
        tiptapToMarkdown: markdown.tiptapToMarkdown,
        getDocument: state.getDocument,
        getTitle: state.getTitle,
        getMetadata: state.getMetadata,
        getActiveProfile: helpers.getActiveProfile,
        getDataDir: helpers.getDataDir,
        getDocId: state.getDocId,
        platformFetch: connections.platformFetch,
    };
    return _cached;
}
// markdown-it instance matching export-routes.ts configuration
export const md = new MarkdownIt({ linkify: false, html: true });
md.enable('strikethrough');
md.use(markdownItIns);
md.use(markdownItMark);
md.use(markdownItSub);
md.use(markdownItSup);
/** Strip YAML frontmatter and TipTap empty markers from markdown output */
export function stripFrontmatter(markdown) {
    let result = markdown;
    const fmMatch = result.match(/^---\n[\s\S]*?\n---\n\n/);
    if (fmMatch)
        result = result.slice(fmMatch[0].length);
    result = result.replace(/^\s*<!--\s*-->\s*$/gm, '');
    return result.trim();
}
/** Scan HTML for /_images/ references, read local files, return base64 array for R2 upload */
export async function extractLocalImages(html) {
    const server = await getServerModules();
    const dataDir = server.getDataDir();
    const images = [];
    const regex = /\/_images\/[^\s"'<>]+/g;
    const seen = new Set();
    let match;
    while ((match = regex.exec(html)) !== null) {
        const imgPath = match[0];
        if (seen.has(imgPath))
            continue;
        seen.add(imgPath);
        const localFile = join(dataDir, imgPath);
        if (!existsSync(localFile))
            continue;
        const data = readFileSync(localFile).toString('base64');
        const ext = extname(imgPath).toLowerCase();
        const mimeMap = {
            '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg',
            '.png': 'image/png', '.gif': 'image/gif',
            '.webp': 'image/webp', '.svg': 'image/svg+xml',
        };
        images.push({ path: imgPath, data, content_type: mimeMap[ext] || 'image/png' });
    }
    return images;
}
/** Convert current document's TipTap JSON to body HTML + plain text */
export async function documentToEmail() {
    const server = await getServerModules();
    const doc = server.getDocument();
    const title = server.getTitle();
    const metadata = server.getMetadata();
    const raw = server.tiptapToMarkdown(doc, title, metadata);
    const clean = stripFrontmatter(raw).trim();
    const html = md.render(clean);
    const text = markdownToPlainText(clean);
    return { html, text, subject: title, json: doc };
}
/** Strip markdown syntax to produce clean plain text for email */
export function markdownToPlainText(markdown) {
    const lines = markdown.split('\n');
    const out = [];
    let inCodeBlock = false;
    let codeLines = [];
    for (const line of lines) {
        if (/^```/.test(line)) {
            if (inCodeBlock) {
                for (const cl of codeLines)
                    out.push('    ' + cl);
                codeLines = [];
                inCodeBlock = false;
            }
            else {
                inCodeBlock = true;
            }
            continue;
        }
        if (inCodeBlock) {
            codeLines.push(line);
            continue;
        }
        if (/^\s*<!--.*-->\s*$/.test(line))
            continue;
        if (/^!\[.*\]\(.*\)\s*$/.test(line))
            continue;
        if (/^\|[\s:|-]+\|\s*$/.test(line))
            continue;
        if (/^\|(.+)\|\s*$/.test(line)) {
            const cells = line
                .slice(1, -1)
                .split('|')
                .map((c) => stripInline(c.trim()));
            out.push(cells.join(' | '));
            continue;
        }
        if (/^[-*_]{3,}\s*$/.test(line)) {
            out.push('---');
            continue;
        }
        const headerMatch = line.match(/^(#{1,6})\s+(.*)/);
        if (headerMatch) {
            out.push(stripInline(headerMatch[2]));
            continue;
        }
        const bqMatch = line.match(/^(>\s?)+(.*)$/);
        if (bqMatch) {
            out.push(stripInline(bqMatch[2]));
            continue;
        }
        const taskMatch = line.match(/^(\s*)[-*+]\s+\[([ xX])\]\s+(.*)/);
        if (taskMatch) {
            const indent = taskMatch[1];
            const check = taskMatch[2] === ' ' ? '[ ]' : '[x]';
            out.push(indent + check + ' ' + stripInline(taskMatch[3]));
            continue;
        }
        const ulMatch = line.match(/^(\s*)[-*+]\s+(.*)/);
        if (ulMatch) {
            out.push(ulMatch[1] + '- ' + stripInline(ulMatch[2]));
            continue;
        }
        const olMatch = line.match(/^(\s*)(\d+)\.\s+(.*)/);
        if (olMatch) {
            out.push(olMatch[1] + olMatch[2] + '. ' + stripInline(olMatch[3]));
            continue;
        }
        out.push(stripInline(line));
    }
    if (inCodeBlock) {
        for (const cl of codeLines)
            out.push('    ' + cl);
    }
    return out
        .join('\n')
        .replace(/\n{3,}/g, '\n\n')
        .trim();
}
/** Strip inline markdown marks from a string */
export function stripInline(text) {
    return text
        .replace(/!\[([^\]]*)\]\([^)]+\)/g, '')
        .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1 ($2)')
        .replace(/`([^`]+)`/g, '$1')
        .replace(/(\*{3}|_{3})(.+?)\1/g, '$2')
        .replace(/(\*{2}|_{2})(.+?)\1/g, '$2')
        .replace(/(\*|_)(.+?)\1/g, '$2')
        .replace(/~~(.+?)~~/g, '$1')
        .replace(/\+\+(.+?)\+\+/g, '$1')
        .replace(/==(.+?)==/g, '$1')
        .replace(/~([^~]+)~/g, '$1')
        .replace(/\^([^^]+)\^/g, '$1');
}
/** Make an authenticated request to the Publish API via platform proxy */
export async function publishFetch(_config, path, options = {}) {
    const server = await getServerModules();
    return server.platformFetch(path, options);
}
