package Mojolicious::Plugin::Fondation::Group;
$Mojolicious::Plugin::Fondation::Group::VERSION = '0.03';
use Mojo::Base 'Mojolicious::Plugin', -signatures;
use DBIx::Class::Relationship::ManyToMany::Async;

# ABSTRACT: Group management plugin for Fondation

sub fondation_meta {
    return {
        dependencies => [
            'Fondation::Model::DBIx::Async',
            'Fondation::MigrationDBIx',
            ],
        defaults => {
            title           => 'Group Management',
            openapi_exclude => ['UserGroup'],
            models          => {
                group => {
                    source  => 'Group',
                    backend => undef,  # must be set in app config
                },
                user_group => {
                    source  => 'UserGroup',
                    backend => undef,  # must be set in app config
                },
            },
        },
    };
}

sub register ($self, $app, $conf) {
    return $self;
}

sub fondation_finalyze ($self, $app, $long_name) {
    my $registry = $app->fondation->registry;

    # Only establish user↔group relation if User plugin is loaded
    if ($registry->{'Mojolicious::Plugin::Fondation::User'}) {
        # Underlying has_many / belongs_to
        Mojolicious::Plugin::Fondation::User::Schema::Result::User->has_many(
            'user_group',
            'Mojolicious::Plugin::Fondation::Group::Schema::Result::UserGroup',
            'user_id',
        );
        Mojolicious::Plugin::Fondation::Group::Schema::Result::UserGroup->belongs_to(
            'user',
            'Mojolicious::Plugin::Fondation::User::Schema::Result::User',
            { 'foreign.id' => 'self.user_id' },
        );

        many_to_many_async('Mojolicious::Plugin::Fondation::User::Schema::Result::User', 'groups', 'user_group', 'group');
        many_to_many_async('Mojolicious::Plugin::Fondation::Group::Schema::Result::Group', 'users',  'user_group', 'user');
    }

    return 1;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Mojolicious::Plugin::Fondation::Group - Group management plugin for Fondation

=head1 VERSION

version 0.03

=head1 SYNOPSIS

  # myapp.conf
  {
      'Fondation' => {
          dependencies => [
              'Fondation::User',
              'Fondation::Group',
          ],
      },
  }

=head1 DESCRIPTION

L<Mojolicious::Plugin::Fondation::Group> provides group management:
the C<groups> and C<user_group> (pivot) tables, REST controllers,
and automatic many-to-many relations with users and permissions.

=head2 Many-to-many relations

When L<Fondation::User> is loaded, group↔user links are established
automatically in C<fondation_finalyze> via
L<DBIx::Class::Relationship::ManyToMany::Async>.

Similarly, when L<Fondation::Perm> is loaded, group↔perm links are
created in that plugin's C<fondation_finalyze>.

=head2 with() — many_to_many prefetch

  # Include perms (or users) in list/read responses
  GET /api/Group?with=perms
  GET /api/User?with=groups

  # Programmatically:
  $c->model('group')->with('perms')->TO_JSON->then(sub ($data) {
      $self->render(openapi => $data);
  });
  $c->model('user')->with('groups')->TO_JSON->then(sub ($data) {
      $self->render(openapi => $data);
  });

C<with()> triggers a single-query prefetch via the pivot table.
Target objects are auto-included in the C<TO_JSON> output by
L<Mojolicious::Plugin::Fondation::Schema::Result::Base>.

Without C<with()>, m2m relationships are silently excluded.

=head2 Controller

REST endpoints (routes generated by OpenAPI):

  GET    /api/Group           list all groups
  POST   /api/Group           create a group
  GET    /api/Group/:id       read a group
  PUT    /api/Group/:id       update a group
  DELETE /api/Group/:id       delete a group

  GET    /api/Group/:id/members      list members
  POST   /api/Group/:id/members      add a member
  DELETE /api/Group/:id/members/:uid remove a member

=head1 SEE ALSO

=over

=item *

L<Mojolicious::Plugin::Fondation::User>

=item *

L<Mojolicious::Plugin::Fondation::Perm>

=item *

L<DBIx::Class::Relationship::ManyToMany::Async>

=item *

L<Mojolicious::Plugin::Fondation::Schema::Result::Base>

=back

=head1 AUTHOR

Daniel Brosseau <dab@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Daniel Brosseau.

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
