### ----------------------------------------------------
### -- WWW::MermaidInk
### -- Licenses: Artistic-2.0
### -- Authors: Anton Antonov
### -- File: lib/WWW/MermaidInk.rakumod
### ----------------------------------------------------
use v6.d;

unit module WWW::MermaidInk;

use HTTP::Tiny;
use Base64;

#| Makes an image from Mermaid-Ink (https://mermaid.ink).
#| C<$spec> -- Mermaid-JS diagram specification.
#| C<:$file> -- File name to export the diagram image to.
#| C<:sub(:$subdomain)> -- Subdomain for mermaid.ink, one of 'svg', 'img', or Whatever.
#| C<:bgColor(:$background)> -- String that is a hexadecimal color number or a named color prefixed with "!".
#| C<:$format> -- Format of the obtained image; one of <base64 md-image md-url hash>.
proto sub mermaid-ink(Str $spec, |) is export {*}

multi sub mermaid-ink(Str $spec,
                      :$file is copy = '',
                      :sub(:$subdomain) is copy = Whatever,
                      Str :bgColor(:$background) is copy = 'FFFFFF',
                      Str :$format = 'asis') {

    # Process subdomain
    my $svgNames = <svg vector vector-graphics scalable-vector-graphics>;
    if $subdomain.isa(Whatever) {
        $subdomain = $format.lc ∈ $svgNames ?? 'svg' !! 'img';
    }
    die 'The argument $type is expected to be one of "img", "svg", or Whatever.'
    unless $subdomain ~~ Str:D && $subdomain.lc ∈ <img svg>;
    $subdomain = $subdomain.lc;

    # Process background
    if !($background ~~ / ^ <[0..9 A..F]>+ $ /) && ($background ~~ / ^ <[a..z A..Z]>+ $ /) {
        $background = '!' ~ $background;
    }
    die 'The argument $background is expected to be' ~
            ' a hexadecimal color number or a named HTML color.'
    unless ($background ~~ / ^ <[0..9 A..F]>+ $ /) || ($background ~~ / ^ '!' <[a..z A..Z]>+ $ /);

    # Process file
    if $file.isa(Whatever) { $file = $*CWD ~ '/out.png'; }
    die 'The argument $file is expected to be a (valid file) string, file handle, or Whatever.'
    unless $file ~~ Str || $file ~~ IO::Handle;

    # Make URL
    my $url = "https://mermaid.ink/$subdomain/{encode-base64($spec):str}?bgColor=$background";

    # Retrieve
    my $resp = HTTP::Tiny.get: $url;

    if $resp<success> && $file {
        # Export
        spurt $file, $resp.<content>;
    }

    given $format {
        if $_ ∈ $svgNames {
            if $subdomain eq 'svg'  {
                return $resp.<content>.decode;
            } else {
                note "When \$format is one of '{$svgNames.join("', '")}', then \$subdomain is expected to be 'svg' or Whatever.";
                return $resp;
            }
        }
        when $_.lc ∈ <base64 b64_json> {
            return $resp.<content>.&encode-base64(:str);
        }
        when $_.lc ∈ <md-image image-md markdown> {
            return '![](data:image/png;base64,' ~ $resp.<content>.&encode-base64(:str) ~ ')';
        }
        when $_.lc ∈ <md-url url-md markdown-url url> {
            return "![]({$resp.<url>})";
        }
        when $_.lc ∈ <hash asis> {
            return $resp;
        }
        default {
            note "Do not know what to do with the specified format, ⎡{$format.raku}⎦.";
            return $resp;
        }
    }
}

multi sub mermaid-ink(@edges where @edges.all ~~ Pair, :$file is copy = '', Str :$format = 'asis', :$directive is copy = Whatever ) {
    my $spec = 'graph';
    if $directive ~~ Str {
        $spec ~= " $directive";
    }

    for @edges -> $e {
        $spec ~= "\n{$e.key} --> {$e.value}";
    }

    return mermaid-ink($spec, :$file, :$format);
}


