<?php

namespace Database\Seeders;

use App\Models\Permission;
use App\Models\Role;
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;

/**
 * Roles and permissions from PRD 5 and 6.
 *
 * Permissions are the unit of authorisation; roles are only bundles of them,
 * so a new job title never requires a code change.
 */
class RolePermissionSeeder extends Seeder
{
    /** group => [slug => label] */
    protected array $permissions = [
        'Applications' => [
            'applications.view' => 'View applications',
            'applications.review' => 'Review applications',
            'applications.approve' => 'Approve admissions',
            'applications.reject' => 'Reject applications',
            'applications.assign' => 'Assign reviewers',
            'applications.export' => 'Export applications',
        ],
        'Applicants' => [
            'applicants.view' => 'View applicants',
            'applicants.update' => 'Update applicant records',
        ],
        'Documents' => [
            'documents.view' => 'View applicant documents',
            'documents.verify' => 'Verify documents',
        ],
        'Programmes' => [
            'programmes.view' => 'View programmes',
            'programmes.create' => 'Create programmes',
            'programmes.update' => 'Update programmes',
            'programmes.delete' => 'Delete programmes',
        ],
        'Intakes' => [
            'intakes.view' => 'View intakes',
            'intakes.manage' => 'Manage intakes',
        ],
        'Payments' => [
            'payments.view' => 'View payments',
            'payments.verify' => 'Verify payments',
            'payments.refund' => 'Refund payments',
            'payments.export' => 'Export financial reports',
        ],
        'Admissions' => [
            'admissions.view' => 'View admissions',
            'admissions.generate' => 'Generate admission documents',
        ],
        'Content' => [
            'content.view' => 'View content',
            'content.create' => 'Create content',
            'content.update' => 'Update content',
            'content.publish' => 'Publish content',
            'content.delete' => 'Delete content',
        ],
        'Administration' => [
            'users.manage' => 'Manage users',
            'roles.manage' => 'Manage roles and permissions',
            'settings.manage' => 'Manage settings',
            'reports.view' => 'View reports',
            'audit.view' => 'View audit logs',
        ],
    ];

    /** role slug => [name, description, permission slugs] */
    protected function roles(): array
    {
        $all = collect($this->permissions)->flatMap(fn (array $p) => array_keys($p))->all();

        return [
            Role::SUPER_ADMIN => [
                'Super Administrator',
                'Unrestricted access to every part of the platform.',
                $all,
            ],
            Role::ADMISSIONS_MANAGER => [
                'Admissions Manager',
                'Runs the admissions cycle and approves final admission decisions.',
                [
                    'applications.view', 'applications.review', 'applications.approve',
                    'applications.reject', 'applications.assign', 'applications.export',
                    'applicants.view', 'applicants.update',
                    'documents.view', 'documents.verify',
                    'programmes.view', 'intakes.view', 'intakes.manage',
                    'payments.view', 'admissions.view', 'admissions.generate',
                    'reports.view', 'audit.view',
                ],
            ],
            Role::ADMISSIONS_OFFICER => [
                'Admissions Officer',
                'Reviews applications and recommends decisions.',
                [
                    'applications.view', 'applications.review', 'applications.reject',
                    'applications.export',
                    'applicants.view',
                    'documents.view', 'documents.verify',
                    'programmes.view', 'intakes.view',
                    'payments.view', 'admissions.view', 'admissions.generate',
                ],
            ],
            Role::FINANCE_OFFICER => [
                'Finance Officer',
                'Verifies and reconciles application payments.',
                [
                    'applications.view', 'applicants.view',
                    'payments.view', 'payments.verify', 'payments.refund', 'payments.export',
                    'reports.view',
                ],
            ],
            Role::PROGRAMME_ADMIN => [
                'Programme Administrator',
                'Maintains the programme catalogue and entry requirements.',
                [
                    'programmes.view', 'programmes.create', 'programmes.update', 'programmes.delete',
                    'intakes.view', 'intakes.manage', 'reports.view',
                ],
            ],
            Role::CONTENT_EDITOR => [
                'Content Editor',
                'Manages the public website content.',
                [
                    'content.view', 'content.create', 'content.update',
                    'content.publish', 'content.delete',
                ],
            ],
        ];
    }

    public function run(): void
    {
        foreach ($this->permissions as $group => $items) {
            foreach ($items as $slug => $name) {
                Permission::updateOrCreate(['slug' => $slug], [
                    'name' => $name,
                    'group' => $group,
                ]);
            }
        }

        foreach ($this->roles() as $slug => [$name, $description, $permissionSlugs]) {
            $role = Role::updateOrCreate(['slug' => $slug], [
                'name' => $name,
                'description' => $description,
                'is_system' => true,
            ]);

            $role->permissions()->sync(
                Permission::whereIn('slug', $permissionSlugs)->pluck('id')
            );
        }

        $this->command?->info(sprintf(
            'Seeded %d permissions across %d roles.',
            Permission::count(),
            Role::count(),
        ));
    }
}
