package System::Introspector::Report::Publish::MediaWiki::Producer;
use Moo;
use HTML::Zoom;

sub render {
  my ($self, $stream) = @_;
  return $self->_clear_body(join "\n", map {
    ref($_) ? $self->_render_table($_) : $_;
  } @$stream);
}

sub _clear_body {
  my ($self, $string) = @_;
  $string =~ s{\n\n+}{\n\n}g;
  return $string;
}

sub _wrap {
  my ($self, $type, $id, $body) = @_;
  chomp $body;
  return join "\n",
    sprintf('<!-- SI:%s begin %s -->', uc($type), $id),
    $body,
    sprintf('<!-- SI:%s end %s -->', uc($type), $id),
}

sub _render_table {
  my ($self, $report) = @_;
  my $id     = $report->{id};
  my $str_id = ref($id) ? join(':', @$id) : $id;
  my $markup = $self->_load_markup;
  $markup = $self->_apply_table_head($markup, $report);
  $markup = $self->_apply_table_body($markup, $report);
  my $description = $report->{description} || [''];
  return join "\n",
    $self->_wrap('title', $str_id, $self->_render_title($report)),
    @$description,
    $self->_wrap('table', $str_id, $markup->to_html),
    '';
}

sub _render_title {
  my ($self, $report) = @_;
  return sprintf '== %s ==', $report->{title};
}

my $_prepare_column_content = sub {
  my ($content) = @_;
  return ''
    unless defined $content;
  my @lines = split m{\n}, $content;
  if (@lines == 1) {
    return $content;
  }
  else {
    my ($first, @rest) = @lines;
    return HTML::Zoom->from_events([
      { type => 'TEXT', raw => $first },
      map {
        my $string = $_;
        ( @{ HTML::Zoom->from_html('<br/>')->to_events },
          { type => 'TEXT', raw => $string });
      } @rest,
    ]);
  }
};

sub _apply_table_body {
  my ($self, $markup, $report) = @_;
  my $index = 0;
  my $rows  = $report->{rows};
  my @cols  = map $_->{key}, @{$report->{columns}};
  return $markup->repeat('.data-row', sub {
    return HTML::Zoom::CodeStream->new({
      code => sub {
        return if $index > $#$rows;
        my $row = $rows->[$index++];
        return sub {
          $_->repeat('td', [ map {
            my $col_idx = $_;
            my $col = $cols[$_];
            my $value = $row->{$col};
            sub {
              $_->apply_if($col !~ m{^__}, sub {
                  $_->add_to_attribute('td', class => "si-column-$col");
                })
                ->replace_content('td', $value->$_prepare_column_content)
                ->apply_if($col_idx != $#cols, sub {
                  $_->add_after('td', "\n    ");
                });
            };
          } 0 .. $#cols ]);
        };
      },
    });
  })->memoize;
}

my $_trim = sub {
  my $string = shift;
  $string =~ s{(?:^\s+|\s+$)}{}g;
  return $string;
};

sub _apply_table_head {
  my ($self, $markup, $report) = @_;
  my @cols = @{$report->{columns}};
  return $markup
    ->repeat('th', [map {
      my $col_idx = $_;
      my $col = $cols[$_];
      my $label = $col->{label};
      sub {
        $_->apply_if($col->{key} !~ m{^__}, sub {
            $_->add_to_attribute('th', class => 'si-colhead-' . $col->{key});
          })
          ->replace_content('th', defined($label) ? $label->$_trim : 'Unnamed')
          ->apply_if($col_idx != $#cols, sub {
            $_->add_after('th', "\n    ");
          });
      };
    } 0 .. $#cols ])
    ->memoize;
}

my $_template = do {
  local $/;
  scalar <DATA>;
};

sub _load_markup {
  return HTML::Zoom->from_html($_template);
}

1;

__DATA__
<table class="si-report">
  <tr>
    <th>Header</th>
  </tr>
  <tr class="data-row">
    <td>Value</td>
  </tr>
</table>
