import c from 'chalk';
import { UtilsAi } from "../aiProvider/utils.js";
import { uxLog } from "../utils/index.js";
import { AiProvider } from '../aiProvider/index.js';
import { XMLParser } from 'fast-xml-parser';
import fs from 'fs-extra';
import path from 'path';
import { getMetaHideLines, includeFromFile } from './docUtils.js';
import { CONSTANTS } from '../../config/index.js';
export class DocBuilderRoot {
    docType;
    promptKey;
    placeholder;
    xmlRootKey;
    docsSection;
    metadataName;
    metadataXml = "";
    outputFile;
    additionalVariables;
    markdownDoc;
    parsedXmlObject;
    constructor(metadataName, metadataXml, outputFile, additionalVariables = {}) {
        this.metadataName = metadataName;
        this.metadataXml = metadataXml;
        this.outputFile = outputFile;
        this.additionalVariables = additionalVariables;
    }
    // This method must be overridden
    async buildInitialMarkdownLines() {
        return [];
    }
    async generateMarkdownFileFromXml() {
        if (this.xmlRootKey === 'json') {
            this.parsedXmlObject = this.metadataXml;
        }
        else if (this.xmlRootKey) {
            this.parsedXmlObject = new XMLParser().parse(this.metadataXml)?.[this.xmlRootKey] || {};
        }
        const mdLines = [
            '<!-- This file is auto-generated. if you do not want it to be overwritten, set TRUE in the line below -->',
            '<!-- DO_NOT_OVERWRITE_DOC=FALSE -->',
            ''
        ];
        // Main lines generated by overridden method
        const initialMdLines = await this.buildInitialMarkdownLines();
        mdLines.push(...initialMdLines);
        // Footer
        mdLines.push("");
        mdLines.push(`_Documentation generated with [sfdx-hardis](${CONSTANTS.DOC_URL_ROOT}), by [Cloudity](https://www.cloudity.com/) & [friends](https://github.com/hardisgroupcom/sfdx-hardis/graphs/contributors)_`);
        this.markdownDoc = mdLines.join("\n") + "\n";
        this.markdownDoc = await this.completeDocWithAiDescription();
        await fs.ensureDir(path.dirname(this.outputFile));
        let overwriteDoc = true;
        if (fs.existsSync(this.outputFile)) {
            const fileContent = await fs.readFile(this.outputFile, "utf8");
            if (fileContent.includes("DO_NOT_OVERWRITE_DOC=TRUE")) {
                uxLog("warning", this, c.yellow(`The file ${this.outputFile} is marked as DO_NOT_OVERWRITE_DOC=TRUE. Skipping generation.`));
                overwriteDoc = false;
            }
        }
        if (overwriteDoc) {
            await fs.writeFile(this.outputFile, getMetaHideLines() + this.markdownDoc);
            uxLog("success", this, c.green(`Successfully generated ${this.metadataName} documentation into ${this.outputFile}`));
        }
        const jsonTree = await this.generateJsonTree();
        if (jsonTree) {
            const jsonFile = `./docs/json/${this.docsSection}-${this.metadataName}.json`;
            await fs.ensureDir(path.dirname(jsonFile));
            await fs.writeFile(jsonFile, JSON.stringify(jsonTree, null, 2));
            uxLog("success", this, c.green(`Successfully generated ${this.metadataName} JSON into ${jsonFile}`));
            // Recovery to save git repos: Kill existing file if it has been created with forbidden characters
            if (this.docsSection === "packages") {
                const jsonFileBad = `./docs/json/${this.docsSection}-${this.metadataName}.json`;
                if (jsonFileBad !== jsonFile && fs.existsSync(jsonFileBad)) {
                    await fs.remove(jsonFileBad);
                }
            }
        }
        return this.outputFile;
    }
    async completeDocWithAiDescription() {
        const xmlStripped = await this.stripXmlForAi();
        const aiCache = await UtilsAi.findAiCache(this.promptKey, [xmlStripped], this.metadataName);
        if (aiCache.success === true) {
            uxLog("log", this, c.grey(`Used AI cache for ${this.docType.toLowerCase()} description (set IGNORE_AI_CACHE=true to force call to AI)`));
            const replaceText = `## AI-Generated Description\n\n${includeFromFile(aiCache.aiCacheDirFile, aiCache.cacheText || "")}`;
            this.markdownDoc = this.markdownDoc.replace(this.placeholder, replaceText);
            return this.markdownDoc;
        }
        if (AiProvider.isAiAvailable()) {
            const defaultVariables = { [`${this.docType.toUpperCase()}_NAME`]: this.metadataName, [`${this.docType.toUpperCase()}_XML`]: xmlStripped };
            const variables = Object.assign(defaultVariables, this.additionalVariables);
            const prompt = AiProvider.buildPrompt(this.promptKey, variables);
            /* jscpd:ignore-start */
            const aiResponse = await AiProvider.promptAi(prompt, this.promptKey);
            if (aiResponse?.success) {
                let responseText = aiResponse.promptResponse || "No AI description available";
                if (responseText.startsWith("##")) {
                    responseText = responseText.split("\n").slice(1).join("\n");
                }
                await UtilsAi.writeAiCache(this.promptKey, [xmlStripped], this.metadataName, responseText);
                const replaceText = `## AI-Generated Description\n\n${includeFromFile(aiCache.aiCacheDirFile, responseText)}`;
                this.markdownDoc = this.markdownDoc.replace(this.placeholder, replaceText);
                return this.markdownDoc;
            }
            /* jscpd:ignore-end */
            else if (aiResponse?.forcedTimeout) {
                const forcedTimeoutText = `CI job reached maximum time allowed for allowed calls to AI. You can either:

    - Run command locally then commit + push
    - Increase using variable \`AI_MAX_TIMEOUT_MINUTES\` in your CI config (ex: AI_MAX_TIMEOUT_MINUTES=120) after making sure than your CI job timeout can handle it :)`;
                const replaceText = `## AI-Generated Description\n\n${includeFromFile(aiCache.aiCacheDirFile, forcedTimeoutText)}`;
                this.markdownDoc = this.markdownDoc.replace(this.placeholder, replaceText);
            }
        }
        return this.markdownDoc;
    }
    // Override this method if you need to make a smaller XML to fit in the number of prompt tokens
    async stripXmlForAi() {
        return this.metadataXml;
    }
    // Override this method if you need to generate a JSON tree for the doc
    async generateJsonTree() {
        return null;
    }
}
//# sourceMappingURL=docBuilderRoot.js.map