#!/usr/bin/env raku
use CSS::Minifier;

my %*SUB-MAIN-OPTS = :named-anywhere, :numeric-suffix-as-value, :allow-no;

my sub validate-level(Str $val) {
    die "Invalid --level value; expected 1 or 2, got '$val'" unless $val ~~ /^<[12]>$/;
}

sub ARGS-TO-CAPTURE(&main, @args --> Capture) {
    my @new;
    my $i = 0;
    while $i < @args {
        my $arg = @args[$i];
        if $arg eq '-l' || $arg eq '--level' {
            if $i + 1 < @args && @args[$i+1] ~~ /^<[12]>$/ {
                @new.push: "--level=@args[$i+1]";
                $i += 2;
                next;
            }
            validate-level(@args[$i+1] // '???');
        } elsif $arg ~~ /^ '--level' \= (\d+) $/ {
            validate-level(~$0);
            @new.push: $arg;
            $i++;
            next;
        } elsif $arg eq '-o' || $arg eq '--output' {
            if $i + 1 < @args && @args[$i+1] !~~ /^'-'/ {
                @new.push: "--output=@args[$i+1]";
                $i += 2;
                next;
            }
            die "Missing file path for $arg";
        }
        @new.push: @args[$i++];
    }
    &*ARGS-TO-CAPTURE(&main, @new)
}

multi sub MAIN(Bool :$version!) { #= Print version and exit
    say CSS::Minifier.^ver
}

multi sub MAIN(
    Str :o(:$output),         #= Write to file instead of stdout
    Int :l(:$level) = 2,      #= Optimization level: 1 (safe normalizations) or 2 (structural optimizations)
    Bool :p(:$preserve-licenses), #= Keep /*! */ license comments (prepended to output)
    Bool :n(:$color-names),   #= Convert hex colors to named colors where possible
    Bool :m(:$color-masks) = True, #= Enable hex color shortening (use --no-color-masks to disable)
    Bool :r(:$readable),      #= Separate rules with newlines (default: one line)
    Bool :v(:$verbose),       #= Show plugin names during processing

    *@files                   #= CSS files to read (reads from stdin if none given)
) {
    if !@files && $*IN.t {
        note "No input: pass CSS files or pipe via stdin";
        note $*USAGE;
        exit 1;
    }
    my $css = @files
        ?? @files.map({ try { .IO.slurp } // do { note "Cannot read $_"; exit 1 } }).join("\n")
        !! $*IN.slurp;

    my $src-hint = @files ?? @files.join(', ') !! '<stdin>';
    my $minified = do {
        CATCH { default { note "Failed to minify $src-hint: $_"; exit 1 } }
        CSS::Minifier.minify($css,
            :$level,
            :$verbose,
            :$preserve-licenses,
            :$color-masks,
            :$color-names,
            |(:sep("\n") if $readable),
        );
    };

    with $output { .IO.spurt($minified) }
    else         { $minified.print }
}

=begin pod

=head1 NAME

cssminify - CSS minifier CLI

=head1 SYNOPSIS

cssminify [--level=<n>] [--output=<file>] [--preserve-licenses] [--color-names] [--readable] [--verbose] [<file> ...]

Also accepts short flags: -o, -l, -p, -n, -m, -r, -v.

=head1 DESCRIPTION

Reads CSS from files or stdin, minifies it, and writes to stdout or a file.

=head2 Options

=item C<-l|--level> - Optimization level: 1 (safe normalizations) or 2 (structural optimizations, default)
=item C<-o|--output> - Write to file instead of stdout
=item C<-p|--preserve-licenses> - Keep license comments (extracted before parse, prepended to output)
=item C<-n|--color-names> - Convert hex colors to named colors where possible
=item C<--color-masks> / C<--no-color-masks> (short: C<-m>) - Enable/disable hex color shortening (when both C<--color-names> and C<--color-masks> are given, C<--color-names> takes precedence)
=item C<-r|--readable> - Separate rules with newlines (default: one line)
=item C<-v|--verbose> - Log plugin names to stderr during processing
=item C<--version> - Print version and exit

=head2 Examples

    cssminify input.css > output.css
    cssminify -l2 input.css -o output.css
    cssminify -r -p input.css
    cat input.css | cssminify --color-names

=head1 AUTHOR

Sasha Abbott <sashaa@disroot.org>

=head1 COPYRIGHT AND LICENSE

This library is free software; you can redistribute it and/or modify it under CC0.

=end pod
