package Pod::Weaver::Plugin::Module::Features;

our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
our $DATE = '2021-04-06'; # DATE
our $DIST = 'Pod-Weaver-Plugin-Module-Features'; # DIST
our $VERSION = '0.002'; # VERSION

use 5.010001;
use Moose;
with 'Pod::Weaver::Role::AddTextToSection';
with 'Pod::Weaver::Role::Section';

#has include_module => (is=>'rw');
#has exclude_module => (is=>'rw');

use Data::Dmp;

sub _md2pod {
    require Markdown::To::POD;

    my ($self, $md) = @_;
    my $pod = Markdown::To::POD::markdown_to_pod($md);
    # make sure we add a couple of blank lines in the end
    $pod =~ s/\s+\z//s;
    $pod . "\n\n\n";
}

sub _process_module {
    no strict 'refs';

    my ($self, $document, $input, $package) = @_;

    my $filename = $input->{filename};

  LOAD_MODULE:
    {
        # XXX handle dynamically generated module (if there is such thing in the
        # future)
        local @INC = ("lib", @INC);
        my $package_pm = $package;
        $package_pm =~ s!::!/!g;
        $package_pm .= ".pm";
        require $package_pm;
    }

  RENDER_FEATURE_SET_SPEC:
    {
        last unless $package =~ /^Module::Features::/;

        require Data::Sah::Util::Type;

        my $feature_set_spec = \%{"$package\::FEATURES_DEF"};
        last unless keys %$feature_set_spec;

        # add Defined Features section
        {
            my @fnames = sort keys %{ $feature_set_spec->{features} };
            last unless @fnames;
            my @pod;
            push @pod, "Features defined by this module:\n\n";
            push @pod, "=over\n\n";
            for my $fname (@fnames) {
                my $fspec = $feature_set_spec->{features}{$fname};
                push @pod, "=item * $fname\n\n";
                my $req = $fspec->{req};
                push @pod, $req ? "Required. " : "Optional. ";
                my $type = Data::Sah::Util::Type::get_type($fspec->{schema} // 'bool');
                push @pod, "Type: $type. ";
                push @pod, "$fspec->{summary}. " if $fspec->{summary};
                if ($fspec->{description}) {
                    push @pod, $self->_md2pod($fspec->{description});
                } else {
                    push @pod, "\n\n";
                }
            }
            push @pod, "=back\n\n";

            push @pod, "For more details on module features, see L<Module::Features>.\n\n";

            $self->add_text_to_section(
                $document, join("", @pod), 'DEFINED FEATURES',
                {
                    after_section => ['VERSION', 'NAME'],
                    before_section => 'DESCRIPTION',
                    ignore => 1,
                });
        } # Defined Features section

        # add Description section
        {
            my @pod;
            push @pod, $self->_md2pod($feature_set_spec->{description}) if $feature_set_spec->{description};

            $self->add_text_to_section(
                $document, join("", @pod), 'DESCRIPTION',
                {
                    after_section => ['SYNOPSIS'],
                    ignore => 1,
                });
        } # Description section
    } # RENDER_FEATURE_SET_SPEC

  RENDER_FEATURES_DECL:
    {
        require Data::Dmp;
        require Data::Sah::Util::Type;
        require Module::FeaturesUtil::Get;
        require String::PodQuote;

        my $features_decl = Module::FeaturesUtil::Get::get_features_decl($package, 'load');
        my $source = delete $features_decl->{'x.source'};
        last unless $source && (keys %$features_decl);

        $source =~ s/^pm://;

        # add Declared Features section
        {
            my @fsetnames = sort keys %{ $features_decl->{features} };
            last unless @fsetnames;
            my @pod;
            push @pod, "Features declared by this module";
            push @pod, " (actually declared in L<$source>)" if $source ne $package;
            push @pod, " (actually declared for L<$1>)" if $package =~ /^(.+)::_ModuleFeatures$/;
            push @pod, ":\n\n";
            for my $fsetname (@fsetnames) {
                push @pod, "=head2 From feature set $fsetname\n\n";
                push @pod, "Features from feature set L<$fsetname|Module::Features::$fsetname> declared by this module:\n\n";

                my $feature_set_spec = Module::FeaturesUtil::Get::get_feature_set_spec($fsetname, 'load');
                my $set_features = $features_decl->{features}{$fsetname};
                my @fnames = sort keys %$set_features;
                push @pod, "=over\n\n";
                for my $fname (@fnames) {
                    my $fspec = $feature_set_spec->{features}{$fname};
                    push @pod, "=item * $fname\n\n";
                    if (defined $fspec->{summary}) {
                        require String::PodQuote;
                        push @pod, String::PodQuote::pod_quote($fspec->{summary}), ".\n\n";
                    }
                    if ($fspec->{description}) {
                        require Markdown::To::POD;
                        push @pod, _md2pod($fspec->{description});
                    }
                    my $type = Data::Sah::Util::Type::get_type($fspec->{schema} // 'bool');
                    my $fval = Module::FeaturesUtil::Get::get_feature_val($package, $fsetname, $fname);
                    if (!defined($fval)) {
                        $fval = "N/A (not defined)";
                    } elsif ($type eq 'bool') {
                        $fval = $fval ? "yes" : "no";
                    } else {
                        $fval = Data::Dmp::dmp($fval);
                    }
                    push @pod, "Value: ".String::PodQuote::pod_escape($fval).".\n\n";
                } # for fname
                push @pod, "=back\n\n";
            } # for fsetname
            push @pod, "For more details on module features, see L<Module::Features>.\n\n";

            $self->add_text_to_section(
                $document, join("", @pod), 'DECLARED FEATURES',
                {
                    after_section => ['VERSION', 'NAME'],
                    before_section => 'DESCRIPTION',
                    ignore => 1,
                });
        } # Declared Features section
    } # RENDER_FEATURES_DECL

    $self->log(["Generated POD for '%s'", $filename]);
}

sub weave_section {
    my ($self, $document, $input) = @_;

    my $filename = $input->{filename};

    my $package;
    if ($filename =~ m!(?:lib/)?(.+)\.pm$!) {
        $package = $1;
        $package =~ s!/!::!g;
        #if ($self->include_module && @{ $self->include_module }) {
        #    return unless grep {$_ eq $package} @{ $self->include_module };
        #}
        #if ($self->exclude_module && @{ $self->exclude_module }) {
        #    return if grep {$_ eq $package} @{ $self->exclude_module };
        #}
        $self->_process_module($document, $input, $package);
    }
}

1;
# ABSTRACT: Plugin to use when building distribution that has feature definer or featurer declarer modules

__END__

=pod

=encoding UTF-8

=head1 NAME

Pod::Weaver::Plugin::Module::Features - Plugin to use when building distribution that has feature definer or featurer declarer modules

=head1 VERSION

This document describes version 0.002 of Pod::Weaver::Plugin::Module::Features (from Perl distribution Pod-Weaver-Plugin-Module-Features), released on 2021-04-06.

=head1 SYNOPSIS

In your F<weaver.ini>:

 [-Module::Features]

=head1 DESCRIPTION

This plugin is to be used when building distribution that has feature definer or
featurer declarer modules. For more details on module features, see
L<Module::Features>. Currently it does the following:

For feature defined modules (C<Module::Features::*> modules):

=over

=item * Add a description in the feature definer's Description section

=item * Add a Defined Features section

=back

For feature defined modules:

=over

=item * Add a Declared Features section for a feature declarer module

=back

=for Pod::Coverage .*

=head1 CONFIGURATION

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Pod-Weaver-Plugin-Module-Features>.

=head1 SOURCE

Source repository is at L<https://github.com/perlancar/perl-Pod-Weaver-Plugin-Module-Features>.

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website L<https://github.com/perlancar/perl-Pod-Weaver-Plugin-Module-Features/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 SEE ALSO

L<Module::Features>

L<Dist::Zilla::Plugin::Module::Features>

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2021 by perlancar@cpan.org.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
