type Html<M> =
    | Element(String, List<Attr<M>>, List<Html<M>>)
    | Text(String)
    | Empty

type Attr<M> =
    | Class(String)
    | Id(String)
    | OnClick(M)

fn div<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> = Element("div", attrs, children)

fn span<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> = Element("span", attrs, children)

fn h1<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> = Element("h1", attrs, children)

fn button<M>(attrs: List<Attr<M>>, children: List<Html<M>>): Html<M> = Element("button", attrs, children)

fn text<M>(content: String): Html<M> = Text(content)

fn class<M>(name: String): Attr<M> = Class(name)

fn onClick<M>(msg: M): Attr<M> = OnClick(msg)

type Model =
    | Counter(Int)

fn getCount(model: Model): Int =
    match model {
    Counter(n) => n,
}

fn init(): Model = Counter(0)

type Msg =
    | Increment
    | Decrement
    | Reset

fn update(model: Model, msg: Msg): Model =
    match msg {
    Increment => Counter(getCount(model) + 1),
    Decrement => Counter(getCount(model) - 1),
    Reset => Counter(0),
}

fn viewCounter(count: Int): Html<Msg> = {
    let countText = text(toString(count))
    let countSpan = span([class("count")], [countText])
    let displayDiv = div([class("counter-display")], [countSpan])
    let minusBtn = button([onClick(Decrement), class("btn")], [text("-")])
    let resetBtn = button([onClick(Reset), class("btn btn-reset")], [text("Reset")])
    let plusBtn = button([onClick(Increment), class("btn")], [text("+")])
    let buttonsDiv = div([class("counter-buttons")], [minusBtn, resetBtn, plusBtn])
    let title = h1([], [text("Counter")])
    div([class("counter-app")], [title, displayDiv, buttonsDiv])
}

fn view(model: Model): Html<Msg> = viewCounter(getCount(model))

fn showAttr(attr: Attr<Msg>): String =
    match attr {
    Class(s) => "class=\"" + s + "\"",
    Id(s) => "id=\"" + s + "\"",
    OnClick(msg) => match msg {
    Increment => "onclick=\"Increment\"",
    Decrement => "onclick=\"Decrement\"",
    Reset => "onclick=\"Reset\"",
},
}

fn showAttrs(attrs: List<Attr<Msg>>): String =
    match List.head(attrs) {
    None => "",
    Some(a) => match List.tail(attrs) {
    None => showAttr(a),
    Some(rest) => showAttr(a) + " " + showAttrs(rest),
},
}

fn showChildren(children: List<Html<Msg>>, indent: Int): String =
    match List.head(children) {
    None => "",
    Some(c) => match List.tail(children) {
    None => showHtml(c, indent),
    Some(rest) => showHtml(c, indent) + showChildren(rest, indent),
},
}

fn showHtml(html: Html<Msg>, indent: Int): String =
    match html {
    Empty => "",
    Text(s) => s,
    Element(tag, attrs, children) => {
    let attrStr = showAttrs(attrs)
    let attrPart = if String.length(attrStr) > 0 then " " + attrStr else ""
    let childStr = showChildren(children, indent + 2)
    "<" + tag + attrPart + ">" + childStr + "</" + tag + ">"
},
}

fn main(): Unit with {Console} = {
    let model = init()
    Console.print("=== Counter App (TEA Pattern) ===")
    Console.print("")
    Console.print("Initial count: " + toString(getCount(model)))
    Console.print("")
    let m1 = update(model, Increment)
    Console.print("After Increment: " + toString(getCount(m1)))
    let m2 = update(m1, Increment)
    Console.print("After Increment: " + toString(getCount(m2)))
    let m3 = update(m2, Increment)
    Console.print("After Increment: " + toString(getCount(m3)))
    let m4 = update(m3, Decrement)
    Console.print("After Decrement: " + toString(getCount(m4)))
    let m5 = update(m4, Reset)
    Console.print("After Reset: " + toString(getCount(m5)))
    Console.print("")
    Console.print("=== View (HTML Structure) ===")
    Console.print(showHtml(view(m2), 0))
}

let output = run main() with {}
