use Mojo::Base -strict;

use Test::More;
use Test::Mojo;
use utils::RBAC;
use utils::JWT;

# 1. Test Client vs Staff Role and Type Identification
my $admin_staff = {
  id        => 1,
  email     => 'admin@anchor.com',
  role      => 'admin',
  user_type => 'staff',
};

my $supporter_staff = {
  id        => 2,
  email     => 'support@anchor.com',
  role      => 'supporter',
  user_type => 'staff',
};

my $client_user = {
  id        => 10,
  email     => 'client@example.com',
  role      => 'client',
  user_type => 'client',
};

# Role predicates
ok(utils::RBAC::is_admin($admin_staff), 'Admin in staff table is admin');
ok(!utils::RBAC::is_admin($supporter_staff), 'Supporter in staff table is not admin');
ok(!utils::RBAC::is_admin($client_user), 'Client in clients table is not admin');

ok(utils::RBAC::is_supporter($supporter_staff), 'Supporter identified as supporter');
ok(!utils::RBAC::is_supporter($admin_staff), 'Admin is not supporter');
ok(!utils::RBAC::is_supporter($client_user), 'Client is not supporter');

ok(utils::RBAC::is_staff($admin_staff), 'Admin is staff');
ok(utils::RBAC::is_staff($supporter_staff), 'Supporter is staff');
ok(!utils::RBAC::is_staff($client_user), 'Client is not staff');

ok(utils::RBAC::is_client($client_user), 'Client identified as client');
ok(!utils::RBAC::is_client($admin_staff), 'Admin is not client');
ok(!utils::RBAC::is_client($supporter_staff), 'Supporter is not client');

# 2. Test RBAC Permissions Resolution for Separate Tables
is(utils::RBAC::has_permission(undef, $admin_staff, 'clients.view'), 1, 'Admin has clients.view');
is(utils::RBAC::has_permission(undef, $admin_staff, 'staff.manage'), 1, 'Admin has staff.manage');
is(utils::RBAC::has_permission(undef, $admin_staff, 'tickets.delete'), 1, 'Admin has tickets.delete');

is(utils::RBAC::has_permission(undef, $client_user, 'tickets.view_own'), 1, 'Client has tickets.view_own');
is(utils::RBAC::has_permission(undef, $client_user, 'profile.view_own'), 1, 'Client has profile.view_own');
is(utils::RBAC::has_permission(undef, $client_user, 'clients.view'), 0, 'Client denied clients.view');
is(utils::RBAC::has_permission(undef, $client_user, 'staff.manage'), 0, 'Client denied staff.manage');

# 3. Test Mock Database for Staff Permissions Mapping (staff_permissions table)
{
  package MockStaffDB;
  sub new { bless {}, shift }
  sub query {
    my ($self, $sql, $staff_id, $slug) = @_;
    my $granted = ($staff_id == 2 && $slug eq 'tickets.reply') ? 1 : 0;
    return MockStaffRes->new($granted);
  }

  package MockStaffRes;
  sub new { my ($class, $has_row) = @_; bless { has_row => $has_row }, $class }
  sub can { my ($self, $method) = @_; return $method eq 'hash' ? 1 : 0 }
  sub hash { my ($self) = @_; return $self->{has_row} ? { id => 1 } : undef }
}

my $mock_staff_db = MockStaffDB->new;
is(utils::RBAC::has_permission($mock_staff_db, $supporter_staff, 'tickets.reply'), 1, 'Supporter with tickets.reply in staff_permissions is allowed');
is(utils::RBAC::has_permission($mock_staff_db, $supporter_staff, 'clients.delete'), 0, 'Supporter without clients.delete in staff_permissions is denied');

# 4. Mojolicious Application Endpoints Testing
my $t = Test::Mojo->new('AnchorBackend');
my $config = $t->app->config;

# Test Staff Auth Endpoint Validation
$t->post_ok('/api/admin/auth/login' => json => {})
  ->status_is(400)
  ->json_is('/status' => 'error');

$t->post_ok('/api/admin/login' => json => {})
  ->status_is(400)
  ->json_is('/status' => 'error');

$t->post_ok('/api/admin/auth/login' => json => { email => 'invalid-email', password => '123456' })
  ->status_is(400)
  ->json_is('/status' => 'error');

# Client JWT Token
my $client_jwt = utils::JWT::generate($config, {
  user_id    => 10,
  email      => 'client@example.com',
  first_name => 'Client',
  last_name  => 'User',
  role       => 'client',
  user_type  => 'client',
});

# Admin JWT Token
my $admin_jwt = utils::JWT::generate($config, {
  user_id    => 1,
  email      => 'admin@anchor.com',
  first_name => 'Admin',
  last_name  => 'Staff',
  role       => 'admin',
  user_type  => 'staff',
});

# Verify Client is strictly blocked from Admin/Staff endpoints
$t->post_ok('/api/admin/staff/list' => { Authorization => "Bearer $client_jwt" } => json => {})
  ->status_is(403)
  ->json_is('/status' => 'error');

$t->post_ok('/api/admin/staff/create' => { Authorization => "Bearer $client_jwt" } => json => { email => 'test@anchor.com' })
  ->status_is(403)
  ->json_is('/status' => 'error');

$t->post_ok('/api/admin/permissions' => { Authorization => "Bearer $client_jwt" } => json => {})
  ->status_is(403)
  ->json_is('/status' => 'error');

$t->post_ok('/api/admin/clients/list' => { Authorization => "Bearer $client_jwt" } => json => {})
  ->status_is(403)
  ->json_is('/status' => 'error');

# Verify Admin Token can access Admin endpoints (validation error 400 when missing body, not 403 Forbidden)
$t->post_ok('/api/admin/staff/create' => { Authorization => "Bearer $admin_jwt" } => json => {})
  ->status_is(400)
  ->json_is('/status' => 'error');

done_testing();
