#!/usr/bin/env perl -w

use strict;
use warnings;
use lib 'lib';
use lib 'extlib';
use open qw(:utf8);
use File::Spec;
use Encode;
use MT;
use MT::Util qw(encode_js);
use File::Find;

my @files = ();

push @files, find_js(
    directories => ['mt-static/'],
    extensions  => ['js', 'tag'],
    ignore      => [
        'mt-static/js/common/DOM',
        'mt-static/mt_ja.js',
        'mt-static/mt_en_us.js',
    ],
);

push @files, find_js(
    directories => ['src/'],
    extensions  => ['svelte', 'ts'],
);

push @files, find_js(
    directories => [
        'tmpl/',
        glob('plugins/*/tmpl'),
        glob('addons/*/tmpl'),
    ],
    extensions  => ['tmpl'],
);

my $addon_path = File::Spec->catdir('addons');
my @addons;
if ( opendir my $dh, $addon_path ) {
    my @p = readdir $dh;
    foreach my $p (@p) {
        next if $p eq '.' || $p eq '..';
        my $full_path = File::Spec->catdir( $addon_path, $p );
        if ( -d $full_path ) {
            if ( $p =~ m/^(.+)\.(\w+)$/ ) {
                my $label = $1;
                my $type  = $2;
                next if $type ne 'pack';
                push @addons, $label;
            }
        }
    }
    closedir $dh;
}

my $plugin_path = File::Spec->catdir('plugins');
my @plugins;
if ( opendir my $dh, $plugin_path ) {
    my @p = readdir $dh;
    foreach my $p (@p) {
        next if $p eq '.' || $p eq '..';
        my $full_path = File::Spec->catdir( $plugin_path, $p );
        if ( -d $full_path ) {
            push @plugins, $p;
        }
    }
    closedir $dh;
}

my $js = '';
for my $file (@files) {
    open my $fh, '<', $file or die "$file: $!";
    local $/;
    $js .= <$fh>;
}

foreach my $lang (qw(en_us ja)) {
    eval 'require MT::L10N::' . $lang
        or die "failed to find package MT::L10N::$lang";

    my $lex = eval '\%{ MT::L10N::' . $lang . '::Lexicon }' || {};

    foreach my $addon (@addons) {
        eval {
            unshift @INC, "addons/$addon.pack/lib";
            require "./addons/$addon.pack/lib/MT/$addon/L10N/$lang.pm";
        };
        next if $@;
        my $conv;
        $conv = eval '\%{MT::' . $addon . '::L10N::' . $lang . '::Lexicon}';
        if (%$conv) {
            $lex = { %$lex, %$conv, };
        }
    }

    foreach my $plugin (@plugins) {
        eval {
            unshift @INC, "plugins/$plugin/lib";
            require "./plugins/$plugin/lib/MT/$plugin/L10N/$lang.pm";
        };
        next if $@;
        my $conv;
        $conv = eval '\%{MT::' . $plugin . '::L10N::' . $lang . '::Lexicon}';
        if (%$conv) {
            $lex = { %$lex, %$conv, };
        }
    }

    my $enc_js = Encode::encode_utf8($js);
    $enc_js =~ s/\\'/\t\t/g;
    my %lexicon;
    while ( $enc_js =~ m/trans\(\s*(["'])([^\1|\\\1]+?)\1/g ) {
        my $str = $2;
        $str =~ s/\t\t/'/g;
        my $local = $lex->{$str} ? Encode::encode_utf8( $lex->{$str} ) : $str;
        $str   = encode_js($str);
        $local = encode_js($local);
        next if $str eq $local;
        $str = Encode::decode_utf8($str);
        $local = Encode::decode_utf8($local) unless Encode::is_utf8($local);
        $lexicon{$str} = $local;
    }

    open( my $FOUT, ">", "./mt-static/mt_$lang.js" )
        or die "failed to open mt-static/mt_$lang.js for writing";

    binmode $FOUT, ":utf8";
    print $FOUT
        "/* Movable Type language lexicon for $lang localization. */\n\n";

    for my $text ( sort keys %lexicon ) {
        print $FOUT "Lexicon['$text'] = '$lexicon{$text}';\n";
    }
    close $FOUT;
}

sub find_js {
    my %args      = @_;
    my $home      = $ENV{MT_TEST_ROOT} || $ENV{MT_HOME} || '.';
    my @dirs      = map { File::Spec->catdir($home, $_) } @{ $args{directories} };
    my $ext_re    = join('|', @{ $args{extensions} });
    my $ignore_re = join('|', @{ $args{ignore} || [] });
    my @ret;
    File::Find::find({
            wanted => sub {
                my $file = $File::Find::name;
                return unless -f $file;
                return if $file               =~ /\/\./;
                return unless $file           =~ /\.($ext_re)$/;
                return if $ignore_re && $file =~ /^$ignore_re/;
                my $rel = File::Spec->abs2rel($file, $home);
                push @ret, $rel;
            },
            no_chdir => 1,
            follow   => 1,
        },
        @dirs
    );
    return @ret;
}
