<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class PermissionSeeder extends Seeder
{
    public function run(): void
    {
        $permissions = self::getPermissionsList();

        $now = now();
        foreach ($permissions as $permission) {
            $parts = explode('.', $permission);
            DB::table('permissions')->updateOrInsert(
                ['name' => $permission],
                [
                    'name' => $permission,
                    'module' => $parts[0],
                    'action' => $parts[1] ?? $permission,
                    'created_at' => $now,
                ]
            );
        }

        $this->command->info('Seeded ' . count($permissions) . ' permissions.');

        $rolePermissions = $this->getRolePermissions();

        foreach ($rolePermissions as $roleSlug => $permMap) {
            $roles = DB::table('roles')->where('slug', $roleSlug)->get();
            if ($roles->isEmpty()) {
                continue;
            }

            foreach ($roles as $role) {
                // For wildcard roles, assign ALL permissions with specified scope
                if ($permMap === '*') {
                    $permIds = DB::table('permissions')->pluck('id', 'name')->toArray();
                    $inserts = [];
                    foreach ($permIds as $name => $pid) {
                        $inserts[] = [
                            'role_id' => $role->id,
                            'permission_id' => $pid,
                            'scope' => 'all',
                            'created_at' => $now,
                        ];
                    }
                } else {
                    $allPermIds = DB::table('permissions')->pluck('id', 'name')->toArray();
                    $inserts = [];
                    foreach ($permMap as $permName => $scope) {
                        if (!isset($allPermIds[$permName])) {
                            continue;
                        }
                        $inserts[] = [
                            'role_id' => $role->id,
                            'permission_id' => $allPermIds[$permName],
                            'scope' => $scope,
                            'created_at' => $now,
                        ];
                    }
                }

                DB::table('permission_role')->where('role_id', $role->id)->delete();
                foreach (array_chunk($inserts, 100) as $chunk) {
                    DB::table('permission_role')->insert($chunk);
                }
            }

            $this->command->info("Role '{$roleSlug}': " . count($inserts) . ' permissions assigned.');
        }
    }

    public static function getPermissionsList(): array
    {
        return [
            // Member portal. These MUST be here and not only in the migration
            // that introduced them: this seeder deletes every permission_role
            // row for a role and reinserts its own list, and db:seed runs on
            // EVERY container start when RUN_SEED_ON_FIRST_DEPLOY is true — so
            // a permission the seeder does not know about is granted once and
            // erased at the next deploy.
            'portal.access', 'portal.pay', 'portal.documents', 'portal.requests',
            'payments.approve_proof', 'attendance.scan', 'users.merge',

            // Dashboard
            'dashboard.view', 'dashboard.export',

            // Organizations
            'academies.list', 'academies.show', 'academies.update',
            'branches.list', 'branches.create', 'branches.update', 'branches.delete',
            // Grants the cross-branch executive view, and with it the branch lock.
            'branches.view_all',

            // Identity & Users
            'users.list', 'users.create', 'users.update', 'users.delete', 'users.assign_roles',
            'roles.list', 'roles.create', 'roles.update', 'roles.delete', 'roles.assign_permissions',
            'people.list', 'people.create', 'people.update', 'people.delete', 'people.merge',

            // Participants
            'participants.list', 'participants.create', 'participants.update', 'participants.delete',
            'participants.show', 'participants.view', 'participants.change_status', 'participants.export',
            'participants.view_financial', 'participants.view_attendance',
            'participants.import', 'participants.bulk_status_change',
            'guardians.list', 'guardians.create', 'guardians.update',

            // Training
            'activities.list', 'activities.create', 'activities.update', 'activities.delete',
            'programs.list', 'programs.create', 'programs.update', 'programs.delete', 'programs.show',
            'groups.list', 'groups.create', 'groups.update', 'groups.delete', 'groups.show',
            'groups.manage_enrollments',
            'sessions.list', 'sessions.show', 'sessions.cancel', 'sessions.reschedule',
            'sessions.start', 'sessions.complete', 'sessions.generate',
            'schedules.list', 'schedules.view', 'schedules.manage',
            'enrollments.list', 'enrollments.create', 'enrollments.cancel',
            'enrollments.override', 'enrollments.transfer',
            'holidays.list', 'holidays.create', 'holidays.update', 'holidays.delete',
            'waitlists.manage', 'waitlists.promote',

            // Attendance
            'attendance.list', 'attendance.mark', 'attendance.edit', 'attendance.export',
            'attendance.view_reports',
            'excuses.list', 'excuses.submit', 'excuses.approve', 'excuses.reject',

            // Financial
            'invoices.list', 'invoices.create', 'invoices.update', 'invoices.cancel',
            'invoices.show', 'invoices.view', 'invoices.send', 'invoices.export',
            'payments.list', 'payments.create', 'payments.refund', 'payments.export',
            'transactions.list', 'transactions.export',
            'accounts.list', 'accounts.create', 'accounts.update',
            'wallets.list', 'wallets.view', 'wallets.credit', 'wallets.debit', 'wallets.freeze',
            'payment_plans.list', 'payment_plans.create', 'payment_plans.update',
            'cash_sessions.open', 'cash_sessions.close', 'cash_sessions.list', 'cash_sessions.manage',
            'refunds.initiate', 'refunds.approve',
            'daily_closing.create', 'daily_closing.view',
            'expenses.create', 'expenses.list', 'expenses.view',
            // Settling an account writes payments, waives balances and bills
            // months nobody billed — the academy's decision, not the desk's.
            'settlements.manage',
            // Where every collected pound lands in the ledger, and what part of
            // it was tax. Viewing explains a figure; managing moves every
            // future collection in the academy.
            'revenue_routing.view', 'revenue_routing.manage',

            // Pricing
            'pricing.list', 'pricing.create', 'pricing.update', 'pricing.delete',
            // Declining a discount a participant qualifies for is a separate act
            // from applying one — and manual discounts need their own approval gate.
            'pricing.discount_remove', 'pricing.discount_approve', 'pricing.simulate',
            'base_prices.list', 'base_prices.manage',
            'pricing_rules.list', 'pricing_rules.manage',
            'promotions.list', 'promotions.create', 'promotions.update', 'promotions.delete',
            'coupons.list', 'coupons.generate', 'coupons.deactivate',

            // POS
            'pos.access', 'pos.sell', 'pos.list',
            'pos.override_price', 'pos.override_stock', 'pos.void_transaction',
            'pos_sessions.open', 'pos_sessions.close', 'pos_sessions.list',

            // Inventory
            'products.list', 'products.create', 'products.update', 'products.delete', 'products.export',
            'categories.list', 'categories.manage',
            'warehouses.list', 'warehouses.create', 'warehouses.update',
            'inventory.list', 'inventory.create', 'inventory.update',
            'inventory.view_levels', 'inventory.adjust', 'inventory.transfer',
            'purchase_orders.list', 'purchase_orders.create', 'purchase_orders.approve', 'purchase_orders.receive',
            'stock_counts.list', 'stock_counts.create', 'stock_counts.approve',
            'kits.list', 'kits.create', 'kits.update', 'kits.delete',
            'suppliers.list', 'suppliers.create', 'suppliers.update',

            // Facilities
            'facilities.list', 'facilities.create', 'facilities.update', 'facilities.delete', 'facilities.show',
            'facilities.manage_layouts', 'facilities.manage_hours',
            'reservations.list', 'reservations.create', 'reservations.cancel', 'reservations.confirm',

            // HR - Employees
            'employees.list', 'employees.create', 'employees.update', 'employees.delete',
            'employees.show', 'employees.change_status', 'employees.export',

            // HR - Trainers
            'trainers.list', 'trainers.create', 'trainers.update', 'trainers.delete',
            'trainers.show', 'trainers.manage_qualifications', 'trainers.manage_availability',
            'trainers.view_compensation',

            // Payroll
            'payroll.manage', 'payroll.view', 'payroll.approve', 'payroll.pay',

            // Assignments
            'assignments.list', 'assignments.create', 'assignments.update', 'assignments.cancel',

            // Notifications
            'notifications.send', 'notifications.manage', 'notifications.manage_templates',
            'notification_preferences.manage',

            // Reports
            'reports.view', 'reports.financial', 'reports.attendance', 'reports.enrollment',
            'reports.inventory', 'reports.trainer', 'reports.facility',
            'reports.export_pdf', 'reports.export_excel',

            // Approvals
            'approvals.list', 'approvals.approve', 'approvals.reject', 'approvals.configure',

            // Settings
            'settings.manage', 'settings.view', 'settings.view_audit_log',

            // Evaluations
            'evaluations.list', 'evaluations.create', 'evaluations.update', 'evaluations.manage',
            'evaluations.approve', 'evaluations.share',

            // Documents
            'documents.list', 'documents.view', 'documents.upload', 'documents.approve', 'documents.delete',

            // Audit
            'audit.list', 'audit.view', 'audit.export',

            // Events
            'events.list', 'events.create', 'events.view', 'events.update',
            'events.manage', 'events.export',

            // Super Admin
            'super_admin.access',
        ];
    }

    /**
     * Role → Permission mappings with per-permission scopes.
     * '*' means all permissions with 'all' scope.
     * Otherwise: ['permission.name' => 'scope', ...]
     */
    private function getRolePermissions(): array
    {
        return [
            'super_admin' => '*',
            'academy_owner' => '*',
            'academy_admin' => $this->academyAdminPermissions(),
            'branch_manager' => $this->branchManagerPermissions(),
            'head_trainer' => $this->headTrainerPermissions(),
            'trainer' => $this->trainerPermissions(),
            'receptionist' => $this->receptionistPermissions(),
            'accountant' => $this->accountantPermissions(),
            'data_entry' => $this->dataEntryPermissions(),
            'parent' => $this->parentPermissions(),
            'player' => $this->playerPermissions(),
        ];
    }

    private function academyAdminPermissions(): array
    {
        $excluded = ['roles.delete', 'super_admin.access'];
        $all = self::getPermissionsList();
        $map = [];
        foreach ($all as $perm) {
            if (!in_array($perm, $excluded)) {
                $map[$perm] = 'all';
            }
        }
        return $map;
    }

    private function branchManagerPermissions(): array
    {
        $allPerms = self::getPermissionsList();
        $allowedModules = [
            'participants', 'guardians', 'activities', 'programs', 'groups',
            'sessions', 'schedules', 'enrollments', 'attendance', 'excuses',
            'invoices', 'payments', 'wallets', 'cash_sessions', 'pricing',
            'pos', 'pos_sessions', 'inventory', 'products', 'warehouses',
            'categories', 'kits', 'facilities', 'reservations', 'assignments',
            'evaluations', 'notifications', 'reports', 'audit',
            'purchase_orders', 'stock_counts', 'suppliers',
            'employees', 'trainers',
        ];

        $map = [];
        foreach ($allPerms as $perm) {
            $module = explode('.', $perm)[0];
            if (in_array($module, $allowedModules)) {
                $map[$perm] = 'branch';
            }
        }

        // Extras with specific scopes
        $map['dashboard.view'] = 'branch';
        $map['dashboard.export'] = 'branch';
        $map['holidays.list'] = 'academy';
        $map['settings.view'] = 'branch';
        $map['users.list'] = 'branch';
        $map['users.create'] = 'branch';
        $map['users.update'] = 'branch';

        return $map;
    }

    private function headTrainerPermissions(): array
    {
        // Start with all trainer permissions
        $map = $this->trainerPermissions();

        // Additional permissions at branch scope
        $branchPerms = [
            'sessions.cancel', 'sessions.reschedule', 'sessions.generate',
            'schedules.list', 'schedules.manage',
            'attendance.edit', 'attendance.export', 'attendance.scan',
            'evaluations.manage', 'evaluations.approve', 'evaluations.share',
            'groups.manage_enrollments',
            'assignments.list', 'assignments.create',
            'excuses.list', 'excuses.approve', 'excuses.reject',
            'participants.view_attendance', 'participants.view_financial',
            'trainers.list', 'trainers.show', 'trainers.manage_availability',
        ];
        foreach ($branchPerms as $perm) {
            $map[$perm] = 'branch';
        }

        return $map;
    }

    private function trainerPermissions(): array
    {
        return [
            'dashboard.view' => 'academy',
            'sessions.list' => 'own_groups',
            'sessions.show' => 'own_groups',
            'sessions.start' => 'own_groups',
            'sessions.complete' => 'own_groups',
            'attendance.list' => 'own_groups',
            'attendance.mark' => 'own_groups',
            'attendance.scan' => 'own_groups',
            'attendance.view_reports' => 'own_groups',
            'groups.list' => 'own_groups',
            'groups.show' => 'own_groups',
            'evaluations.list' => 'own_groups',
            'evaluations.create' => 'own_groups',
            'evaluations.update' => 'own_groups',
            'participants.list' => 'own_groups',
            'participants.show' => 'own_groups',
            'participants.view' => 'own_groups',
            'participants.view_attendance' => 'own_groups',
            'schedules.view' => 'own_groups',
            'excuses.submit' => 'own_groups',
        ];
    }

    private function receptionistPermissions(): array
    {
        return [
            'dashboard.view' => 'branch',
            'participants.list' => 'branch',
            'participants.show' => 'branch',
            'participants.view' => 'branch',
            'participants.create' => 'branch',
            'participants.update' => 'branch',
            'guardians.list' => 'branch',
            'guardians.create' => 'branch',
            'enrollments.list' => 'branch',
            'enrollments.create' => 'branch',
            'activities.list' => 'academy',
            'programs.list' => 'academy',
            'attendance.scan' => 'branch',
            'pos.access' => 'branch',
            'pos.sell' => 'branch',
            'pos.list' => 'branch',
            'invoices.list' => 'branch',
            'invoices.show' => 'branch',
            'invoices.view' => 'branch',
            'invoices.create' => 'branch',
            'payments.create' => 'branch',
            'wallets.view' => 'branch',
            'cash_sessions.open' => 'branch',
            'cash_sessions.close' => 'branch',
            'cash_sessions.list' => 'branch',
            'attendance.list' => 'branch',
            'schedules.view' => 'branch',
        ];
    }

    private function accountantPermissions(): array
    {
        $map = [
            'dashboard.view' => 'academy',
            'participants.list' => 'academy',
            'participants.show' => 'academy',
            'participants.view' => 'academy',
            'enrollments.list' => 'academy',
            'programs.list' => 'academy',
            'pricing.list' => 'academy',
        ];

        // Full financial suite at academy scope
        $financialPerms = [
            'invoices.list', 'invoices.create', 'invoices.update', 'invoices.cancel',
            'invoices.show', 'invoices.view', 'invoices.send', 'invoices.export',
            'payments.list', 'payments.create', 'payments.refund', 'payments.export',
            'transactions.list', 'transactions.export',
            'accounts.list', 'accounts.create', 'accounts.update',
            'wallets.list', 'wallets.view', 'wallets.credit', 'wallets.debit', 'wallets.freeze',
            'payment_plans.list', 'payment_plans.create', 'payment_plans.update',
            'cash_sessions.open', 'cash_sessions.close', 'cash_sessions.list', 'cash_sessions.manage',
            'refunds.initiate', 'refunds.approve',
            // Approving a transfer proof is the moral equivalent of taking
            // cash; the maker-checker rule in PaymentProofService is what
            // stops it being a one-person act.
            'payments.approve_proof',
            'settlements.manage',
            'revenue_routing.view', 'revenue_routing.manage',
            'daily_closing.create', 'daily_closing.view',
            'expenses.create', 'expenses.list', 'expenses.view',
            'reports.financial', 'reports.view', 'reports.export_pdf', 'reports.export_excel',
        ];
        foreach ($financialPerms as $perm) {
            $map[$perm] = 'academy';
        }

        return $map;
    }

    private function dataEntryPermissions(): array
    {
        return [
            'dashboard.view' => 'academy',
            'participants.list' => 'branch',
            'participants.create' => 'branch',
            'participants.update' => 'branch',
            'participants.show' => 'branch',
            'participants.view' => 'branch',
            'guardians.list' => 'branch',
            'guardians.create' => 'branch',
            'guardians.update' => 'branch',
            'people.list' => 'branch',
            'people.create' => 'branch',
            'people.update' => 'branch',
            'activities.list' => 'academy',
            'programs.list' => 'academy',
            'groups.list' => 'branch',
            'enrollments.list' => 'branch',
            'enrollments.create' => 'branch',
        ];
    }

    private function parentPermissions(): array
    {
        return [
            'dashboard.view' => 'academy',
            'attendance.list' => 'own_children',
            'participants.view' => 'own_children',
            'participants.show' => 'own_children',
            'evaluations.list' => 'own_children',
            'invoices.list' => 'own_children',
            'invoices.view' => 'own_children',
            'payments.list' => 'own_children',
            'wallets.view' => 'own_children',
            'programs.list' => 'academy',
            'schedules.view' => 'own_children',
            'excuses.submit' => 'own_children',
            'portal.access' => 'own_children',
            'portal.pay' => 'own_children',
            'portal.documents' => 'own_children',
            'portal.requests' => 'own_children',
        ];
    }

    /**
     * A member who plays for himself.
     *
     * Same scope as a parent, because `own_children` means "the participants
     * this account speaks for" — which GuardianResolver resolves to the account
     * holder's own participant row when there is no guardian. Without this role
     * a player given the `parent` role sees empty lists everywhere.
     */
    private function playerPermissions(): array
    {
        return [
            'dashboard.view' => 'academy',
            'programs.list' => 'academy',
            'attendance.list' => 'own_children',
            'participants.view' => 'own_children',
            'participants.show' => 'own_children',
            'evaluations.list' => 'own_children',
            'invoices.list' => 'own_children',
            'invoices.view' => 'own_children',
            'payments.list' => 'own_children',
            'wallets.view' => 'own_children',
            'schedules.view' => 'own_children',
            'excuses.submit' => 'own_children',
            'portal.access' => 'own_children',
            'portal.pay' => 'own_children',
            'portal.documents' => 'own_children',
            'portal.requests' => 'own_children',
        ];
    }
}
