#
# Strikethrough extension: ~~text~~
#

"""Strikethrough text. Contains inline children."""
struct Strikethrough <: AbstractInline end

is_container(::Strikethrough) = true

Node(::Type{Strikethrough}, children...) = _build(Strikethrough(), children)

"""
    StrikethroughRule()

Parse strikethrough text (`~~deleted~~`).

Not enabled by default. Uses double tildes to mark deleted text.

```markdown
~~This text is struck through.~~
```
"""
struct StrikethroughRule end

parse_tilde(parser, block) = handle_delim(parser, '~', block)

inline_rule(::StrikethroughRule) = Rule(parse_tilde, 1, "~")
inline_modifier(::StrikethroughRule) = Rule(process_emphasis, 1)
delim_nodes(::StrikethroughRule) = Dict(('~', 2) => Strikethrough)
flanking_rule(::StrikethroughRule) = ('~', :standard)

#
# Writers
#

write_html(::Strikethrough, r, n, ent) =
    tag(r, ent ? "del" : "/del", ent ? attributes(r, n) : [])

function write_latex(::Strikethrough, w, n, ent)
    # Requires \usepackage{soul} or \usepackage{ulem}
    return print(w.buffer, ent ? "\\sout{" : "}")
end

function write_typst(::Strikethrough, w, n, ent)
    return print(w.buffer, ent ? "#strike[" : "]")
end

function write_term(::Strikethrough, w, n, ent)
    style = crayon"strikethrough"
    return if ent
        print_literal(w, style)
        push_inline!(w, style)
    else
        pop_inline!(w)
        print_literal(w, inv(style))
    end
end

function write_markdown(::Strikethrough, w, n, ent)
    return literal(w, "~~")
end

function write_json(::Strikethrough, ctx, node, enter)
    return if enter
        inlines = Any[]
        push_container!(ctx, inlines)
    else
        inlines = pop_container!(ctx)
        push_element!(ctx, json_el(ctx, "Strikeout", inlines))
    end
end
