"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NLMDView = exports.NLView = void 0;
const chalk_1 = __importDefault(require("chalk"));
const chalk_util_1 = require("../utils/chalk-util");
const marked_utils_1 = require("../utils/marked-utils");
const art_1 = require("../utils/art");
const art_2 = require("../utils/art");
const spinner_1 = require("../utils/spinner");
// token-specific rendering
class NLView {
    constructor() {
        this.genericStyle = chalk_1.default.blue;
        this.highlightStyle = chalk_1.default.redBright.bold;
        this.av = new art_2.Art(this.genericStyle, this.highlightStyle);
    }
    renderNLError(input) {
        const str = this.av.createMessage(input);
        process.stdout.write(str + "\n");
    }
    render(input, isToken = true, colour = "lightGreen") {
        (0, chalk_util_1.chalkRender)(input, colour);
        if (!isToken) {
            process.stdout.write("\n");
        }
    }
    renderNewLine() {
        process.stdout.write("\n");
    }
    renderBgGrayColunm() {
        let width = process.stdout.columns;
        if (width === undefined) {
            width = 3;
        }
        process.stdout.write(chalk_1.default.dim.gray("#".repeat(width)) + "\n");
    }
}
exports.NLView = NLView;
// markdown-specific rendering
class NLMDView {
    constructor() {
        this.spinner = new spinner_1.Spinner();
        this.genericStyle = chalk_1.default.gray;
        this.highlightStyle = chalk_1.default.gray.bold;
        this.av = new art_2.Art(this.genericStyle, this.highlightStyle);
        this.nlView = new NLView();
        this.isCodeBlock = false;
        this.buffer = [];
        this.isFirstRender = true;
    }
    handleStartCB() {
        // const str = processCenterMessage([], {
        //   content: "#",
        //   styler: chalk.dim.gray,
        // });
        // process.stdout.write(chalk.italic(str + "\n"));
        // process.stdout.write("\n");
        this.spinner.start();
    }
    handleStreamCB(token) {
        this.spinner.incrementTokenCounter(token);
        const subTokenArry = token.split("\n");
        for (let ind = 0; ind < subTokenArry.length; ind += 1) {
            const currSubToken = subTokenArry[ind];
            const canFlipState = canFlipCodeBlockState({
                buffer: this.buffer,
                currSubToken,
            });
            if (canFlipState) {
                this.isCodeBlock = !this.isCodeBlock;
            }
            // now at last subToken
            if (ind === subTokenArry.length - 1) {
                if (subTokenArry.length == 1) {
                    // if only one subToken, append
                    this.buffer.push(currSubToken);
                }
                else {
                    // else, start a new token
                    this.buffer = [currSubToken];
                }
                continue;
            }
            else {
                this.buffer.push(currSubToken);
                const bufferStr = this.buffer.join("");
                // now either at start or middle of the overarching token
                // render as normally with normal conditionals
                if (this.isFirstRender) {
                    this.isFirstRender = false;
                    this.spinner.stop();
                    process.stdout.write("\n");
                    this.spinner.start();
                }
                if (this.isCodeBlock || canFlipState) {
                    // render as codeblock
                    // ora <--- clear & stop
                    this.spinner.stop();
                    this.renderLineNLMDAsCodeBlock(bufferStr);
                    // ora <--- start
                    this.spinner.start();
                }
                else if (bufferStr === "") {
                    // ora <--- clear & stop
                    this.spinner.stop();
                    this.nlView.renderNewLine();
                    // ora <--- start
                    this.spinner.start();
                }
                else {
                    // render normally (if it contains valu)
                    // ora <--- clear & stop
                    this.spinner.stop();
                    this.renderLineNLMD(bufferStr);
                    // ora <--- start
                    this.spinner.start();
                }
                // reset buffer
                this.buffer = [];
            }
        }
    }
    handleEndCB(tokensUsed) {
        const bufferStr = this.buffer.join("");
        if (this.isCodeBlock || bufferStr === "```") {
            // ora <--- clear & stop
            this.spinner.stop();
            this.spinner.resetTokenCounter();
            this.renderLineNLMDAsCodeBlock(bufferStr);
        }
        else {
            // ora <--- clear & stop
            this.spinner.stop();
            this.spinner.resetTokenCounter();
            this.renderLineNLMD(bufferStr);
        }
        this.buffer = [];
        this.isCodeBlock = false;
        // better than av.createMessage
        const str = chalk_1.default.italic((0, art_1.processCenterMessage)([
            { content: "##", styler: chalk_1.default.bold.gray },
            { content: ` ${tokensUsed.toString()}`, styler: chalk_1.default.gray.bold },
            { content: " tokens ", styler: chalk_1.default.gray.bold },
            { content: "##", styler: chalk_1.default.bold.gray },
        ], { content: "#", styler: chalk_1.default.dim.gray }));
        process.stdout.write(str + "\n");
        this.isFirstRender = true;
    }
    renderLineNLMDAsCodeBlock(input) {
        input = this.postProcess(input);
        if (input.startsWith("```")) {
            input = chalk_1.default.gray("```") + chalk_1.default.bold.yellow(input.slice(3));
        }
        else {
            input = chalk_1.default.italic.gray(input);
        }
        process.stdout.write(input + "\n");
    }
    renderLineNLMD(input) {
        this.renderFullNLMD(input);
    }
    renderFullNLMD(input) {
        const mdStr = (0, marked_utils_1.mdLineStr)(input);
        let postProcessedStr = this.postProcess(mdStr);
        process.stdout.write(postProcessedStr);
    }
    postProcess(input) {
        input = input.replace(/<br>/g, "\n");
        const htmlDecode = (input) => {
            for (const [key, value] of Object.entries({
                "&amp;": "&",
                "&lt;": "<",
                "&gt;": ">",
                "&quot;": '"',
                "&#39;": "'",
                // add more if needed
            })) {
                input = input.replace(new RegExp(key, "g"), value);
            }
            return input;
        };
        return htmlDecode(input);
    }
}
exports.NLMDView = NLMDView;
// we know currSubToken is split by "\n"
const canFlipCodeBlockState = ({ currSubToken, buffer, }) => {
    const isFirstThreeBackticks = currSubToken.slice(0, 3) === "```";
    // three backtick case
    if (isFirstThreeBackticks) {
        return true;
    }
    const isFirstTwoBackTicks = currSubToken.slice(0, 2) === "``";
    // two backtick case
    if (isFirstTwoBackTicks) {
        // need to check buffer (enuf len to check last val)
        if (buffer.length >= 1) {
            const lastBufferVal = buffer[buffer.length - 1];
            // this last bufferVal needs to end in a backtick to complete a three-set
            const lastBufferValEndsWithBacktick = lastBufferVal === "`";
            if (lastBufferValEndsWithBacktick) {
                return true;
            }
        }
    }
    const isFirstBackTick = currSubToken[0] === "`";
    // one backtick case
    if (isFirstBackTick) {
        // need to check buffer length
        const lastBufferVal = buffer[buffer.length - 1];
        if (buffer.length >= 2) {
            const penultimateBufferVal = buffer[buffer.length - 2];
            if ((lastBufferVal === "`" && penultimateBufferVal === "`") ||
                lastBufferVal === "``") {
                return true;
            }
        }
        else if (buffer.length >= 1) {
            if (lastBufferVal === "``") {
                return true;
            }
        }
    }
    return false;
};
