/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
// Only slugs verified to return content via the get_document API are included.
// Many newer Industry Cloud docs use a different platform without public API access.
export const PROFILE_DOC_SOURCES = {
    fsc: [{ slug: 'atlas.en-us.financial_services_cloud_object_reference.meta', label: 'FSC Object Reference' }],
    automotive: [{ slug: 'atlas.en-us.automotive_cloud.meta', label: 'Automotive Cloud Guide' }],
    health: [
        { slug: 'atlas.en-us.health_cloud.meta', label: 'Health Cloud Guide' },
        { slug: 'atlas.en-us.health_cloud_object_reference.meta', label: 'Health Cloud Objects' },
    ],
    nonprofit: [{ slug: 'atlas.en-us.nonprofit_cloud.meta', label: 'Nonprofit Cloud Guide' }],
    loyalty: [{ slug: 'atlas.en-us.loyalty.meta', label: 'Loyalty Management Guide' }],
    commerce: [{ slug: 'atlas.en-us.b2b_b2c_comm_dev.meta', label: 'B2B/B2C Commerce Developer Guide' }],
    cpq: [{ slug: 'atlas.en-us.cpq_dev_api.meta', label: 'CPQ Developer Guide' }],
    crma: [{ slug: 'atlas.en-us.bi_dev_guide_ext_data.meta', label: 'CRM Analytics Developer Guide' }],
};
function readSyncMeta(cwd) {
    const metaPath = join(cwd, '.setup-agents', 'docs', '.sync-meta.json');
    if (!existsSync(metaPath))
        return {};
    try {
        return JSON.parse(readFileSync(metaPath, 'utf8'));
    }
    catch {
        return {};
    }
}
function writeSyncMeta(cwd, meta) {
    const metaPath = join(cwd, '.setup-agents', 'docs', '.sync-meta.json');
    writeFileSync(metaPath, JSON.stringify(meta, null, 2));
}
// ─── HTML → Markdown conversion (lightweight) ──────────────────────────────
function htmlToMarkdown(html) {
    let text = html;
    text = text.replace(/<h1[^>]*>(.*?)<\/h1>/gi, '# $1\n\n');
    text = text.replace(/<h2[^>]*>(.*?)<\/h2>/gi, '## $1\n\n');
    text = text.replace(/<h3[^>]*>(.*?)<\/h3>/gi, '### $1\n\n');
    text = text.replace(/<h4[^>]*>(.*?)<\/h4>/gi, '#### $1\n\n');
    text = text.replace(/<strong>(.*?)<\/strong>/gi, '**$1**');
    text = text.replace(/<b>(.*?)<\/b>/gi, '**$1**');
    text = text.replace(/<em>(.*?)<\/em>/gi, '*$1*');
    text = text.replace(/<code>(.*?)<\/code>/gi, '`$1`');
    text = text.replace(/<li[^>]*>(.*?)<\/li>/gi, '- $1\n');
    text = text.replace(/<br\s*\/?>/gi, '\n');
    text = text.replace(/<p[^>]*>(.*?)<\/p>/gi, '$1\n\n');
    text = text.replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi, '[$2]($1)');
    text = text.replace(/<tr[^>]*>(.*?)<\/tr>/gi, '| $1\n');
    text = text.replace(/<t[hd][^>]*>(.*?)<\/t[hd]>/gi, '$1 | ');
    text = text.replace(/<img[^>]*alt="([^"]*)"[^>]*>/gi, '[$1]');
    text = text.replace(/<[^>]+>/g, '');
    text = text.replace(/&amp;/g, '&');
    text = text.replace(/&lt;/g, '<');
    text = text.replace(/&gt;/g, '>');
    text = text.replace(/&quot;/g, '"');
    text = text.replace(/&#39;/g, "'");
    text = text.replace(/&nbsp;/g, ' ');
    text = text.replace(/\n{3,}/g, '\n\n');
    return text.trim();
}
// ─── Fetch logic ───────────────────────────────────────────────────────────
const BASE_URL = 'https://developer.salesforce.com/docs/get_document';
async function fetchAndConvertSource(source, maxPagesPerSource) {
    const response = await fetch(`${BASE_URL}/${source.slug}`);
    if (!response.ok) {
        return { ok: false, error: `${source.label}: HTTP ${response.status}` };
    }
    const data = (await response.json());
    const pages = [];
    pages.push({ id: data.content_document_id, title: data.doc_title || data.title, content: data.content });
    const topPages = extractTopPages(data.toc, source.maxPages ?? maxPagesPerSource);
    for (const page of topPages) {
        try {
            // eslint-disable-next-line no-await-in-loop
            const pageResp = await fetch(`${BASE_URL}/${source.slug}/${page.href}`);
            if (pageResp.ok) {
                // eslint-disable-next-line no-await-in-loop
                const pageData = (await pageResp.json());
                if (pageData.content) {
                    pages.push({ id: page.id, title: page.text, content: pageData.content });
                }
            }
        }
        catch {
            // individual page fetch failed — continue with others
        }
    }
    return { ok: true, pages };
}
// ─── Main sync function ──────────────────────────────────────────────────────
export async function syncProfileDocs(cwd, profile, options = {}) {
    const sources = PROFILE_DOC_SOURCES[profile];
    if (!sources || sources.length === 0) {
        return { profile, synced: 0, failed: 0, files: [], errors: ['No doc sources registered for this profile'] };
    }
    const { force = false, maxPagesPerSource = 5 } = options;
    const docsDir = join(cwd, '.setup-agents', 'docs', profile);
    mkdirSync(docsDir, { recursive: true });
    const meta = readSyncMeta(cwd);
    const result = { profile, synced: 0, failed: 0, files: [], errors: [] };
    for (const source of sources) {
        const metaKey = `${profile}/${source.slug}`;
        if (!force && meta[metaKey])
            continue;
        try {
            // eslint-disable-next-line no-await-in-loop
            const fetchResult = await fetchAndConvertSource(source, maxPagesPerSource);
            if (!fetchResult.ok) {
                result.errors.push(fetchResult.error);
                result.failed++;
                continue;
            }
            const fileName = slugToFilename(source.slug);
            const mdContent = renderDocFile(source.label, fetchResult.pages);
            const filePath = join(docsDir, fileName);
            writeFileSync(filePath, mdContent);
            const indexPath = generateAndWriteIndex(filePath);
            result.files.push(filePath);
            if (indexPath)
                result.files.push(indexPath);
            result.synced++;
            meta[metaKey] = { syncedAt: new Date().toISOString(), pages: fetchResult.pages.length };
        }
        catch (error) {
            const msg = error instanceof Error ? error.message : String(error);
            result.errors.push(`${source.label}: ${msg}`);
            result.failed++;
        }
    }
    writeSyncMeta(cwd, meta);
    return result;
}
export function listSyncableProfiles() {
    return Object.keys(PROFILE_DOC_SOURCES);
}
export function getSyncStatus(cwd) {
    return readSyncMeta(cwd);
}
// ─── Helpers ───────────────────────────────────────────────────────────────
function extractTopPages(toc, max) {
    const pages = [];
    if (!Array.isArray(toc))
        return pages;
    for (const section of toc) {
        if (pages.length >= max)
            break;
        const children = section.children ?? [];
        for (const child of children) {
            if (pages.length >= max)
                break;
            const href = child.a_attr?.href;
            if (child.id && child.text && href) {
                pages.push({ id: child.id, text: child.text, href });
            }
        }
    }
    return pages;
}
function slugToFilename(slug) {
    return (slug
        .replace(/^atlas\.en-us\./, '')
        .replace(/\.meta$/, '')
        .replace(/\./g, '-') + '.md');
}
function renderDocFile(title, pages) {
    const sections = [];
    sections.push(`# ${title}\n`);
    sections.push(`> Synced: ${new Date().toISOString().split('T')[0]}\n`);
    for (const page of pages) {
        sections.push(`---\n\n## ${page.title}\n`);
        sections.push(htmlToMarkdown(page.content));
        sections.push('');
    }
    return sections.join('\n');
}
export function generateDocIndex(filePath) {
    if (!existsSync(filePath))
        return null;
    const content = readFileSync(filePath, 'utf8');
    const lines = content.split('\n');
    const title = lines.find((l) => l.startsWith('# '))?.replace(/^# /, '') ?? filePath;
    const sections = [];
    for (let i = 0; i < lines.length; i++) {
        const match = /^(#{1,4})\s+(.+)/.exec(lines[i]);
        if (match) {
            sections.push({ heading: match[2], level: match[1].length, line: i + 1, endLine: 0 });
        }
    }
    for (let i = 0; i < sections.length; i++) {
        sections[i].endLine = i < sections.length - 1 ? sections[i + 1].line - 1 : lines.length;
    }
    return { file: filePath, title, totalLines: lines.length, sections };
}
export function renderDocIndexAsMarkdown(index) {
    const lines = [];
    lines.push(`# Index: ${index.title}`);
    lines.push(`File: \`${index.file}\` (${index.totalLines} lines)`);
    lines.push('');
    lines.push('| Section | Lines | Range |');
    lines.push('|---------|-------|-------|');
    for (const s of index.sections) {
        const indent = '  '.repeat(s.level - 1);
        const range = `${s.line}–${s.endLine}`;
        const lineCount = s.endLine - s.line + 1;
        lines.push(`| ${indent}${s.heading} | ${lineCount} | ${range} |`);
    }
    lines.push('');
    lines.push('Use `Read({ file_path: "...", offset: <line-1>, limit: <count> })` to read specific sections.');
    return lines.join('\n');
}
export function generateAndWriteIndex(filePath) {
    const index = generateDocIndex(filePath);
    if (!index)
        return null;
    const indexContent = renderDocIndexAsMarkdown(index);
    const indexPath = filePath.replace(/\.md$/, '.index.md');
    writeFileSync(indexPath, indexContent);
    return indexPath;
}
//# sourceMappingURL=docs-sync.js.map