// YAML-like frontmatter parser
// Parses the --- delimited frontmatter block from markdown files

pub type Frontmatter =
    | Frontmatter(String, String, String, String)
    //             title   date    desc    tagsRaw

pub type ParseResult =
    | ParseResult(Frontmatter, String)
    //             front       body

pub fn parse(content: String): ParseResult = {
    let lines = String.lines(content);
    // Skip first --- line, collect key: value pairs until next ---
    let result = List.fold(lines, (false, false, "", "", "", "", ""), fn(acc: (Bool, Bool, String, String, String, String, String), line: String): (Bool, Bool, String, String, String, String, String) => {
        let inFront = acc.0;
        let pastFront = acc.1;
        let title = acc.2;
        let date = acc.3;
        let desc = acc.4;
        let tags = acc.5;
        let body = acc.6;
        if pastFront then
            (inFront, pastFront, title, date, desc, tags, body + line + "\n")
        else if String.trim(line) == "---" then
            if inFront then
                // End of frontmatter
                (false, true, title, date, desc, tags, body)
            else
                // Start of frontmatter
                (true, false, title, date, desc, tags, body)
        else if inFront then {
            // Parse key: value
            match String.indexOf(line, ": ") {
                Some(idx) => {
                    let key = String.trim(String.substring(line, 0, idx));
                    let rawVal = String.trim(String.substring(line, idx + 2, String.length(line)));
                    // Strip surrounding quotes if present
                    let val = if String.startsWith(rawVal, "\"") then
                        String.substring(rawVal, 1, String.length(rawVal) - 1)
                    else
                        rawVal;
                    if key == "title" then
                        (inFront, pastFront, val, date, desc, tags, body)
                    else if key == "date" then
                        (inFront, pastFront, title, val, desc, tags, body)
                    else if key == "description" then
                        (inFront, pastFront, title, date, val, tags, body)
                    else if key == "tags" then
                        (inFront, pastFront, title, date, desc, val, body)
                    else
                        (inFront, pastFront, title, date, desc, tags, body)
                },
                None => (inFront, pastFront, title, date, desc, tags, body)
            }
        } else
            (inFront, pastFront, title, date, desc, tags, body)
    });
    let front = Frontmatter(result.2, result.3, result.4, result.5);
    ParseResult(front, result.6)
}

pub fn getTitle(f: Frontmatter): String =
    match f { Frontmatter(t, _, _, _) => t }

pub fn getDate(f: Frontmatter): String =
    match f { Frontmatter(_, d, _, _) => d }

pub fn getDesc(f: Frontmatter): String =
    match f { Frontmatter(_, _, d, _) => d }

pub fn getTagsRaw(f: Frontmatter): String =
    match f { Frontmatter(_, _, _, t) => t }

pub fn getTags(f: Frontmatter): List<String> =
    match f { Frontmatter(_, _, _, t) =>
        if t == "" then []
        else String.split(t, " ")
    }
