<?php

namespace App\Providers;

use App\Models\User;
use App\Modules\Admin\ActivityLog\Listeners\EmployeeActivityLogListener;
use App\Modules\Admin\ActivityLog\Listeners\LogActivityListener;
use App\Modules\Admin\Tenancy\Events\TenantSubscriptionAffected;
use App\Modules\Admin\Tenancy\Listeners\ForgetTenantModuleCache;
use App\Modules\Admin\Tenancy\Models\Module as TenancyModule;
use App\Modules\Admin\Tenancy\Models\Plan;
use App\Modules\Admin\Tenancy\Models\Tenant;
use App\Modules\Admin\Tenancy\Policies\ModulePolicy;
use App\Modules\Admin\Tenancy\Policies\PlanPolicy;
use App\Modules\Admin\Tenancy\Policies\TenantPolicy;
use App\Modules\Admin\Tenancy\Services\CustomFieldsPlanService;
use App\Modules\Admin\Tenancy\Services\TenantContext;
use App\Modules\Customization\CustomFields\Models\CustomField;
use App\Modules\Customization\CustomFields\Policies\CustomFieldPolicy;
use App\Modules\Dashboard\Services\NotificationCenterService;
use App\Modules\Exports\Events\ExportCompleted;
use App\Modules\Exports\Events\ExportFailed;
use App\Modules\Exports\Events\ExportRequested;
use App\Modules\Exports\Listeners\ExportActivityLogListener;
use App\Modules\Exports\Listeners\ExportNotificationListener;
use App\Modules\Exports\Models\Export;
use App\Modules\Exports\Policies\ExportPolicy;
use App\Modules\HR\Assets\Models\Asset;
use App\Modules\HR\Assets\Policies\AssetPolicy;
use App\Modules\HR\Attendance\Events\AttendanceCorrectionApproved;
use App\Modules\HR\Attendance\Events\AttendanceCorrectionRejected;
use App\Modules\HR\Attendance\Events\AttendanceCorrectionSubmitted;
use App\Modules\HR\Attendance\Listeners\AttendanceCorrectionActivityLogListener;
use App\Modules\HR\Attendance\Listeners\AttendanceCorrectionNotificationListener;
use App\Modules\HR\Attendance\Models\AttendanceCorrectionRequest;
use App\Modules\HR\Attendance\Models\AttendanceException;
use App\Modules\HR\Attendance\Models\AttendanceRecord;
use App\Modules\HR\Attendance\Policies\AttendanceCorrectionRequestPolicy;
use App\Modules\HR\Attendance\Policies\AttendanceExceptionPolicy;
use App\Modules\HR\Attendance\Policies\AttendanceRecordPolicy;
use App\Modules\HR\Compensation\Models\CompensationType;
use App\Modules\HR\Compensation\Models\EmployeeCompensationItem;
use App\Modules\HR\Compensation\Policies\CompensationPolicy;
use App\Modules\HR\Contracts\Models\ContractTemplate;
use App\Modules\HR\Contracts\Models\EmploymentContract;
use App\Modules\HR\Contracts\Policies\ContractTemplatePolicy;
use App\Modules\HR\Contracts\Policies\EmploymentContractPolicy;
use App\Modules\HR\Departments\Events\DepartmentCreated;
use App\Modules\HR\Departments\Events\DepartmentDeleted;
use App\Modules\HR\Departments\Events\DepartmentUpdated;
use App\Modules\HR\Departments\Models\Department;
use App\Modules\HR\Departments\Policies\DepartmentPolicy;
use App\Modules\HR\Employees\Events\EmployeeCreated;
use App\Modules\HR\Employees\Events\EmployeeDeactivated;
use App\Modules\HR\Employees\Events\EmployeeUpdated;
use App\Modules\HR\Employees\Models\Employee;
use App\Modules\HR\Employees\Models\EmployeeEmploymentHistory;
use App\Modules\HR\Employees\Policies\EmployeeEmploymentHistoryPolicy;
use App\Modules\HR\Employees\Policies\EmployeePolicy;
use App\Modules\HR\Employees\Services\EmployeeHierarchyService;
use App\Modules\HR\EmploymentStatuses\Models\EmploymentStatus;
use App\Modules\HR\EmploymentStatuses\Policies\EmploymentStatusPolicy;
use App\Modules\HR\Leave\Events\LeaveRequestCancelled;
use App\Modules\HR\Leave\Events\LeaveRequestHrApproved;
use App\Modules\HR\Leave\Events\LeaveRequestManagerApproved;
use App\Modules\HR\Leave\Events\LeaveRequestRejected;
use App\Modules\HR\Leave\Events\LeaveRequestSubmitted;
use App\Modules\HR\Leave\Listeners\LeaveActivityLogListener;
use App\Modules\HR\Leave\Listeners\LeaveApproverNotificationListener;
use App\Modules\HR\Leave\Models\LeaveRequest;
use App\Modules\HR\Leave\Models\LeaveType;
use App\Modules\HR\Leave\Policies\LeaveRequestPolicy;
use App\Modules\HR\Leave\Policies\LeaveTypePolicy;
use App\Modules\HR\Loans\Events\LoanApproved;
use App\Modules\HR\Loans\Listeners\LoanNotificationListener;
use App\Modules\HR\Loans\Models\Loan;
use App\Modules\HR\Loans\Policies\LoanPolicy;
use App\Modules\HR\Offboarding\Events\OffboardingSubmitted;
use App\Modules\HR\Offboarding\Listeners\OffboardingNotificationListener;
use App\Modules\HR\Offboarding\Models\OffboardingCase;
use App\Modules\HR\Offboarding\Policies\OffboardingPolicy;
use App\Modules\HR\Organization\Models\Branch;
use App\Modules\HR\Organization\Models\CostCenter;
use App\Modules\HR\Organization\Models\JobGrade;
use App\Modules\HR\Organization\Models\Section;
use App\Modules\HR\Organization\Models\Team;
use App\Modules\HR\Organization\Models\WorkLocation;
use App\Modules\HR\Organization\Policies\BranchPolicy;
use App\Modules\HR\Organization\Policies\CostCenterPolicy;
use App\Modules\HR\Organization\Policies\JobGradePolicy;
use App\Modules\HR\Organization\Policies\SectionPolicy;
use App\Modules\HR\Organization\Policies\TeamPolicy;
use App\Modules\HR\Organization\Policies\WorkLocationPolicy;
use App\Modules\HR\Overtime\Events\OvertimeRequestApproved;
use App\Modules\HR\Overtime\Events\OvertimeRequestCancelled;
use App\Modules\HR\Overtime\Events\OvertimeRequestRejected;
use App\Modules\HR\Overtime\Events\OvertimeRequestSubmitted;
use App\Modules\HR\Overtime\Listeners\OvertimeActivityLogListener;
use App\Modules\HR\Overtime\Listeners\OvertimeNotificationListener;
use App\Modules\HR\Overtime\Models\OvertimeRequest;
use App\Modules\HR\Overtime\Policies\OvertimeRequestPolicy;
use App\Modules\HR\Performance\Models\PerformanceCycle;
use App\Modules\HR\Performance\Models\PerformanceReview;
use App\Modules\HR\Performance\Policies\PerformancePolicy;
use App\Modules\HR\PermissionRequests\Events\PermissionRequestApproved;
use App\Modules\HR\PermissionRequests\Events\PermissionRequestRejected;
use App\Modules\HR\PermissionRequests\Events\PermissionRequestSubmitted;
use App\Modules\HR\PermissionRequests\Listeners\PermissionRequestActivityLogListener;
use App\Modules\HR\PermissionRequests\Listeners\PermissionRequestNotificationListener;
use App\Modules\HR\PermissionRequests\Models\PermissionRequest;
use App\Modules\HR\PermissionRequests\Policies\PermissionRequestPolicy;
use App\Modules\HR\Positions\Events\PositionCreated;
use App\Modules\HR\Positions\Events\PositionDeactivated;
use App\Modules\HR\Positions\Events\PositionUpdated;
use App\Modules\HR\Positions\Models\Position;
use App\Modules\HR\Positions\Policies\PositionPolicy;
use App\Modules\HR\Recruitment\Events\RecruitmentApplicationCreated;
use App\Modules\HR\Recruitment\Events\RecruitmentApplicationDeleted;
use App\Modules\HR\Recruitment\Events\RecruitmentApplicationUpdated;
use App\Modules\HR\Recruitment\Events\RecruitmentCandidateCreated;
use App\Modules\HR\Recruitment\Events\RecruitmentCandidateCvCreated;
use App\Modules\HR\Recruitment\Events\RecruitmentCandidateCvDeleted;
use App\Modules\HR\Recruitment\Events\RecruitmentCandidateDeleted;
use App\Modules\HR\Recruitment\Events\RecruitmentCandidateHired;
use App\Modules\HR\Recruitment\Events\RecruitmentCandidateUpdated;
use App\Modules\HR\Recruitment\Events\RecruitmentInterviewCreated;
use App\Modules\HR\Recruitment\Events\RecruitmentInterviewDeleted;
use App\Modules\HR\Recruitment\Events\RecruitmentInterviewScorecardCreated;
use App\Modules\HR\Recruitment\Events\RecruitmentInterviewScorecardDeleted;
use App\Modules\HR\Recruitment\Events\RecruitmentInterviewScorecardUpdated;
use App\Modules\HR\Recruitment\Events\RecruitmentInterviewUpdated;
use App\Modules\HR\Recruitment\Events\RecruitmentJobRequestApproved;
use App\Modules\HR\Recruitment\Events\RecruitmentJobRequestCreated;
use App\Modules\HR\Recruitment\Events\RecruitmentJobRequestDeleted;
use App\Modules\HR\Recruitment\Events\RecruitmentJobRequestUpdated;
use App\Modules\HR\Recruitment\Events\RecruitmentOfferLetterCreated;
use App\Modules\HR\Recruitment\Events\RecruitmentOfferLetterDeleted;
use App\Modules\HR\Recruitment\Events\RecruitmentOfferLetterStatusChanged;
use App\Modules\HR\Recruitment\Events\RecruitmentOfferLetterUpdated;
use App\Modules\HR\Recruitment\Events\RecruitmentVacancyCreated;
use App\Modules\HR\Recruitment\Events\RecruitmentVacancyDeleted;
use App\Modules\HR\Recruitment\Events\RecruitmentVacancyUpdated;
use App\Modules\HR\Recruitment\Listeners\CareerPortalApplicationNotifier;
use App\Modules\HR\Recruitment\Listeners\HiringActivityLogListener;
use App\Modules\HR\Recruitment\Listeners\OfferLetterActivityLogListener;
use App\Modules\HR\Recruitment\Listeners\RecruitmentActivityLogListener;
use App\Modules\HR\Recruitment\Listeners\StartOnboardingOnHireListener;
use App\Modules\HR\Recruitment\Models\RecruitmentApplication;
use App\Modules\HR\Recruitment\Models\RecruitmentCandidate;
use App\Modules\HR\Recruitment\Models\RecruitmentCandidateCv;
use App\Modules\HR\Recruitment\Models\RecruitmentHiring;
use App\Modules\HR\Recruitment\Models\RecruitmentInterview;
use App\Modules\HR\Recruitment\Models\RecruitmentInterviewScorecard;
use App\Modules\HR\Recruitment\Models\RecruitmentJobRequest;
use App\Modules\HR\Recruitment\Models\RecruitmentOfferLetter;
use App\Modules\HR\Recruitment\Models\RecruitmentOnboardingCase;
use App\Modules\HR\Recruitment\Models\RecruitmentVacancy;
use App\Modules\HR\Recruitment\Policies\RecruitmentApplicationPolicy;
use App\Modules\HR\Recruitment\Policies\RecruitmentCandidateCvPolicy;
use App\Modules\HR\Recruitment\Policies\RecruitmentCandidatePolicy;
use App\Modules\HR\Recruitment\Policies\RecruitmentHiringPolicy;
use App\Modules\HR\Recruitment\Policies\RecruitmentInterviewPolicy;
use App\Modules\HR\Recruitment\Policies\RecruitmentInterviewScorecardPolicy;
use App\Modules\HR\Recruitment\Policies\RecruitmentJobRequestPolicy;
use App\Modules\HR\Recruitment\Policies\RecruitmentOfferLetterPolicy;
use App\Modules\HR\Recruitment\Policies\RecruitmentOnboardingCasePolicy;
use App\Modules\HR\Recruitment\Policies\RecruitmentVacancyPolicy;
use App\Modules\HR\Shifts\Events\ShiftAssigned;
use App\Modules\HR\Shifts\Events\ShiftAssignmentEnded;
use App\Modules\HR\Shifts\Events\ShiftCreated;
use App\Modules\HR\Shifts\Events\ShiftDeactivated;
use App\Modules\HR\Shifts\Events\ShiftReactivated;
use App\Modules\HR\Shifts\Events\ShiftUpdated;
use App\Modules\HR\Shifts\Listeners\ShiftActivityLogListener;
use App\Modules\HR\Shifts\Models\Shift;
use App\Modules\HR\Shifts\Policies\ShiftPolicy;
use App\Modules\HR\Training\Models\TrainingCourse;
use App\Modules\HR\Training\Models\TrainingEnrollment;
use App\Modules\HR\Training\Models\TrainingSession;
use App\Modules\HR\Training\Policies\TrainingPolicy;
use App\Modules\Inventory\Models\InventoryAttribute;
use App\Modules\Inventory\Models\Item;
use App\Modules\Inventory\Models\ItemCategory;
use App\Modules\Inventory\Models\Warehouse;
use App\Modules\Inventory\Policies\InventoryAttributePolicy;
use App\Modules\Inventory\Policies\ItemCategoryPolicy;
use App\Modules\Inventory\Policies\ItemPolicy;
use App\Modules\Inventory\Policies\WarehousePolicy;
use App\Modules\Inventory\Stock\Models\InventoryStockTransfer;
use App\Modules\Inventory\Stock\Policies\InventoryStockTransferPolicy;
use App\Modules\Navigation\Services\NavigationMegaGroupComposer;
use App\Modules\Navigation\Services\NavigationMegaMenuSignalService;
use App\Modules\Navigation\Services\NavigationService;
use App\Modules\Operations\Models\OperationalControlEvent;
use App\Modules\Operations\Policies\OperationalControlEventPolicy;
use App\Modules\Payroll\Events\PayrollAdjustmentCreated;
use App\Modules\Payroll\Events\PayrollPeriodFinalized;
use App\Modules\Payroll\Events\PayrollSnapshotsGenerated;
use App\Modules\Payroll\Listeners\PayrollActivityLogListener;
use App\Modules\Payroll\Models\PayrollAdjustment;
use App\Modules\Payroll\Models\PayrollEmployeeSnapshot;
use App\Modules\Payroll\Models\PayrollPeriod;
use App\Modules\Payroll\Policies\PayrollAdjustmentPolicy;
use App\Modules\Payroll\Policies\PayrollEmployeeSnapshotPolicy;
use App\Modules\Payroll\Policies\PayrollPeriodPolicy;
use App\Modules\Procurement\Models\GoodsReceipt;
use App\Modules\Procurement\Models\PurchaseOrder;
use App\Modules\Procurement\Policies\GoodsReceiptPolicy;
use App\Modules\Procurement\Policies\PurchaseOrderPolicy;
use App\Modules\Sales\Models\SalesOrder;
use App\Modules\Sales\Models\SalesReturn;
use App\Modules\Sales\Policies\SalesOrderPolicy;
use App\Modules\Sales\Policies\SalesReturnPolicy;
use App\Modules\Settings\Localization\Models\Language;
use App\Modules\Settings\Localization\Models\Translation;
use App\Modules\Settings\Localization\Policies\LanguagePolicy;
use App\Modules\Settings\Localization\Policies\TranslationPolicy;
use App\Modules\Settings\Rbac\Services\TenantPermissionEvaluator;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(TenantContext::class, fn () => new TenantContext);
    }

    public function boot(): void
    {
        Event::listen(TenantSubscriptionAffected::class, ForgetTenantModuleCache::class);

        Event::listen(DepartmentCreated::class, [LogActivityListener::class, 'handleDepartmentCreated']);
        Event::listen(DepartmentUpdated::class, [LogActivityListener::class, 'handleDepartmentUpdated']);
        Event::listen(DepartmentDeleted::class, [LogActivityListener::class, 'handleDepartmentDeleted']);

        Event::listen(PositionCreated::class, [LogActivityListener::class, 'handlePositionCreated']);
        Event::listen(PositionUpdated::class, [LogActivityListener::class, 'handlePositionUpdated']);
        Event::listen(PositionDeactivated::class, [LogActivityListener::class, 'handlePositionDeactivated']);

        Event::listen(EmployeeCreated::class, [EmployeeActivityLogListener::class, 'handleCreated']);
        Event::listen(EmployeeUpdated::class, [EmployeeActivityLogListener::class, 'handleUpdated']);
        Event::listen(EmployeeDeactivated::class, [EmployeeActivityLogListener::class, 'handleDeactivated']);

        $leaveLog = app(LeaveActivityLogListener::class);
        Event::listen(LeaveRequestSubmitted::class, [$leaveLog, 'handleSubmitted']);
        Event::listen(LeaveRequestManagerApproved::class, [$leaveLog, 'handleManagerApproved']);
        Event::listen(LeaveRequestHrApproved::class, [$leaveLog, 'handleHrApproved']);
        Event::listen(LeaveRequestRejected::class, [$leaveLog, 'handleRejected']);
        Event::listen(LeaveRequestCancelled::class, [$leaveLog, 'handleCancelled']);

        $leaveNotify = app(LeaveApproverNotificationListener::class);
        Event::listen(LeaveRequestSubmitted::class, [$leaveNotify, 'handleSubmitted']);
        Event::listen(LeaveRequestManagerApproved::class, [$leaveNotify, 'handleManagerApproved']);
        Event::listen(LeaveRequestHrApproved::class, [$leaveNotify, 'handleHrApproved']);
        Event::listen(LeaveRequestRejected::class, [$leaveNotify, 'handleRejected']);

        $permLog = app(PermissionRequestActivityLogListener::class);
        Event::listen(PermissionRequestSubmitted::class, [$permLog, 'handleSubmitted']);
        Event::listen(PermissionRequestApproved::class, [$permLog, 'handleApproved']);
        Event::listen(PermissionRequestRejected::class, [$permLog, 'handleRejected']);

        $permNotify = app(PermissionRequestNotificationListener::class);
        Event::listen(PermissionRequestSubmitted::class, [$permNotify, 'handleSubmitted']);
        Event::listen(PermissionRequestApproved::class, [$permNotify, 'handleApproved']);
        Event::listen(PermissionRequestRejected::class, [$permNotify, 'handleRejected']);

        $shiftLog = app(ShiftActivityLogListener::class);
        Event::listen(ShiftCreated::class, [$shiftLog, 'handleCreated']);
        Event::listen(ShiftUpdated::class, [$shiftLog, 'handleUpdated']);
        Event::listen(ShiftDeactivated::class, [$shiftLog, 'handleDeactivated']);
        Event::listen(ShiftReactivated::class, [$shiftLog, 'handleReactivated']);
        Event::listen(ShiftAssigned::class, [$shiftLog, 'handleAssigned']);
        Event::listen(ShiftAssignmentEnded::class, [$shiftLog, 'handleAssignmentEnded']);

        $recruitmentLog = app(RecruitmentActivityLogListener::class);
        Event::listen(RecruitmentCandidateCreated::class, [$recruitmentLog, 'handleCandidateCreated']);
        Event::listen(RecruitmentCandidateUpdated::class, [$recruitmentLog, 'handleCandidateUpdated']);
        Event::listen(RecruitmentCandidateDeleted::class, [$recruitmentLog, 'handleCandidateDeleted']);
        Event::listen(RecruitmentCandidateCvCreated::class, [$recruitmentLog, 'handleCvCreated']);
        Event::listen(RecruitmentCandidateCvDeleted::class, [$recruitmentLog, 'handleCvDeleted']);
        Event::listen(RecruitmentJobRequestCreated::class, [$recruitmentLog, 'handleJobRequestCreated']);
        Event::listen(RecruitmentJobRequestUpdated::class, [$recruitmentLog, 'handleJobRequestUpdated']);
        Event::listen(RecruitmentJobRequestDeleted::class, [$recruitmentLog, 'handleJobRequestDeleted']);
        Event::listen(RecruitmentJobRequestApproved::class, [$recruitmentLog, 'handleJobRequestApproved']);
        Event::listen(RecruitmentVacancyCreated::class, [$recruitmentLog, 'handleVacancyCreated']);
        Event::listen(RecruitmentVacancyUpdated::class, [$recruitmentLog, 'handleVacancyUpdated']);
        Event::listen(RecruitmentVacancyDeleted::class, [$recruitmentLog, 'handleVacancyDeleted']);
        Event::listen(RecruitmentApplicationCreated::class, [$recruitmentLog, 'handleApplicationCreated']);
        Event::listen(RecruitmentApplicationCreated::class, [CareerPortalApplicationNotifier::class, 'handle']);
        Event::listen(RecruitmentApplicationUpdated::class, [$recruitmentLog, 'handleApplicationUpdated']);
        Event::listen(RecruitmentApplicationDeleted::class, [$recruitmentLog, 'handleApplicationDeleted']);
        Event::listen(RecruitmentInterviewCreated::class, [$recruitmentLog, 'handleInterviewCreated']);
        Event::listen(RecruitmentInterviewUpdated::class, [$recruitmentLog, 'handleInterviewUpdated']);
        Event::listen(RecruitmentInterviewDeleted::class, [$recruitmentLog, 'handleInterviewDeleted']);
        Event::listen(RecruitmentInterviewScorecardCreated::class, [$recruitmentLog, 'handleScorecardCreated']);
        Event::listen(RecruitmentInterviewScorecardUpdated::class, [$recruitmentLog, 'handleScorecardUpdated']);
        Event::listen(RecruitmentInterviewScorecardDeleted::class, [$recruitmentLog, 'handleScorecardDeleted']);

        $offerLog = app(OfferLetterActivityLogListener::class);
        Event::listen(RecruitmentOfferLetterCreated::class, [$offerLog, 'handleCreated']);
        Event::listen(RecruitmentOfferLetterUpdated::class, [$offerLog, 'handleUpdated']);
        Event::listen(RecruitmentOfferLetterDeleted::class, [$offerLog, 'handleDeleted']);
        Event::listen(RecruitmentOfferLetterStatusChanged::class, [$offerLog, 'handleStatusChanged']);

        Event::listen(RecruitmentCandidateHired::class, [HiringActivityLogListener::class, 'handle']);
        Event::listen(RecruitmentCandidateHired::class, [StartOnboardingOnHireListener::class, 'handle']);

        $corrLog = app(AttendanceCorrectionActivityLogListener::class);
        Event::listen(AttendanceCorrectionSubmitted::class, [$corrLog, 'handleSubmitted']);
        Event::listen(AttendanceCorrectionApproved::class, [$corrLog, 'handleApproved']);
        Event::listen(AttendanceCorrectionRejected::class, [$corrLog, 'handleRejected']);

        $corrNotify = app(AttendanceCorrectionNotificationListener::class);
        Event::listen(AttendanceCorrectionSubmitted::class, [$corrNotify, 'handleSubmitted']);
        Event::listen(AttendanceCorrectionApproved::class, [$corrNotify, 'handleApproved']);
        Event::listen(AttendanceCorrectionRejected::class, [$corrNotify, 'handleRejected']);

        $otLog = app(OvertimeActivityLogListener::class);
        Event::listen(OvertimeRequestSubmitted::class, [$otLog, 'handleSubmitted']);
        Event::listen(OvertimeRequestApproved::class, [$otLog, 'handleApproved']);
        Event::listen(OvertimeRequestRejected::class, [$otLog, 'handleRejected']);
        Event::listen(OvertimeRequestCancelled::class, [$otLog, 'handleCancelled']);

        $otNotify = app(OvertimeNotificationListener::class);
        Event::listen(OvertimeRequestSubmitted::class, [$otNotify, 'handleSubmitted']);
        Event::listen(OvertimeRequestApproved::class, [$otNotify, 'handleApproved']);
        Event::listen(OvertimeRequestRejected::class, [$otNotify, 'handleRejected']);

        Event::listen(LoanApproved::class, [LoanNotificationListener::class, 'handleApproved']);
        Event::listen(OffboardingSubmitted::class, [OffboardingNotificationListener::class, 'handleSubmitted']);

        $exportLog = app(ExportActivityLogListener::class);
        Event::listen(ExportRequested::class, [$exportLog, 'handleRequested']);
        Event::listen(ExportCompleted::class, [$exportLog, 'handleCompleted']);
        Event::listen(ExportFailed::class, [$exportLog, 'handleFailed']);

        $exportNotify = app(ExportNotificationListener::class);
        Event::listen(ExportCompleted::class, [$exportNotify, 'handleCompleted']);
        Event::listen(ExportFailed::class, [$exportNotify, 'handleFailed']);

        $payrollLog = app(PayrollActivityLogListener::class);
        Event::listen(PayrollSnapshotsGenerated::class, [$payrollLog, 'handleSnapshotsGenerated']);
        Event::listen(PayrollPeriodFinalized::class, [$payrollLog, 'handleFinalized']);
        Event::listen(PayrollAdjustmentCreated::class, [$payrollLog, 'handleAdjustment']);

        View::composer('components.ui.layout.app', function (\Illuminate\View\View $view): void {
            $view->with('navGroups', app(NavigationService::class)->filteredGroups(auth()->user()));
        });

        $headerAndTopnavNav = function (\Illuminate\View\View $view): void {
            $user = auth()->user();
            if ($user === null) {
                $view->with('navNotificationUnreadCount', 0);
                $view->with('navNotificationPreview', collect());
                $view->with('navMegaGroups', []);
                $view->with('navMegaSignals', ['badges' => []]);
                $view->with('navRecentTrail', []);

                return;
            }
            $svc = app(NotificationCenterService::class);
            $view->with('navNotificationUnreadCount', $svc->unreadCount($user));
            $view->with('navNotificationPreview', $svc->latestUnread($user, 5));

            $navGroups = $view->offsetExists('navGroups') ? $view->offsetGet('navGroups') : null;
            if (! is_array($navGroups)) {
                $navGroups = app(NavigationService::class)->filteredGroups($user);
            }
            $view->with(
                'navMegaGroups',
                app(NavigationMegaGroupComposer::class)->compose($navGroups),
            );
            $view->with(
                'navMegaSignals',
                app(NavigationMegaMenuSignalService::class)->forUser($user),
            );
            $view->with('navRecentTrail', session('erp_nav_recent', []));
        };
        View::composer('components.ui.layout.header', $headerAndTopnavNav);
        View::composer('components.ui.layout.topnav', $headerAndTopnavNav);

        Gate::policy(Department::class, DepartmentPolicy::class);
        Gate::policy(Position::class, PositionPolicy::class);
        Gate::policy(EmploymentStatus::class, EmploymentStatusPolicy::class);
        Gate::policy(Branch::class, BranchPolicy::class);
        Gate::policy(Section::class, SectionPolicy::class);
        Gate::policy(Team::class, TeamPolicy::class);
        Gate::policy(JobGrade::class, JobGradePolicy::class);
        Gate::policy(WorkLocation::class, WorkLocationPolicy::class);
        Gate::policy(CostCenter::class, CostCenterPolicy::class);
        Gate::policy(Employee::class, EmployeePolicy::class);
        Gate::policy(EmployeeEmploymentHistory::class, EmployeeEmploymentHistoryPolicy::class);
        Gate::policy(AttendanceRecord::class, AttendanceRecordPolicy::class);
        Gate::policy(AttendanceCorrectionRequest::class, AttendanceCorrectionRequestPolicy::class);
        Gate::policy(Export::class, ExportPolicy::class);
        Gate::policy(PayrollPeriod::class, PayrollPeriodPolicy::class);
        Gate::policy(PayrollAdjustment::class, PayrollAdjustmentPolicy::class);
        Gate::policy(PayrollEmployeeSnapshot::class, PayrollEmployeeSnapshotPolicy::class);
        Gate::policy(AttendanceException::class, AttendanceExceptionPolicy::class);
        Gate::policy(LeaveType::class, LeaveTypePolicy::class);
        Gate::policy(LeaveRequest::class, LeaveRequestPolicy::class);
        Gate::policy(PermissionRequest::class, PermissionRequestPolicy::class);
        Gate::policy(OvertimeRequest::class, OvertimeRequestPolicy::class);
        Gate::policy(EmploymentContract::class, EmploymentContractPolicy::class);
        Gate::policy(ContractTemplate::class, ContractTemplatePolicy::class);
        Gate::policy(Asset::class, AssetPolicy::class);
        Gate::policy(Loan::class, LoanPolicy::class);
        Gate::policy(CompensationType::class, CompensationPolicy::class);
        Gate::policy(EmployeeCompensationItem::class, CompensationPolicy::class);
        Gate::policy(PerformanceCycle::class, PerformancePolicy::class);
        Gate::policy(PerformanceReview::class, PerformancePolicy::class);
        Gate::policy(TrainingCourse::class, TrainingPolicy::class);
        Gate::policy(TrainingSession::class, TrainingPolicy::class);
        Gate::policy(TrainingEnrollment::class, TrainingPolicy::class);
        Gate::policy(OffboardingCase::class, OffboardingPolicy::class);
        Gate::policy(RecruitmentCandidate::class, RecruitmentCandidatePolicy::class);
        Gate::policy(RecruitmentCandidateCv::class, RecruitmentCandidateCvPolicy::class);
        Gate::policy(RecruitmentJobRequest::class, RecruitmentJobRequestPolicy::class);
        Gate::policy(RecruitmentVacancy::class, RecruitmentVacancyPolicy::class);
        Gate::policy(RecruitmentApplication::class, RecruitmentApplicationPolicy::class);
        Gate::policy(RecruitmentInterview::class, RecruitmentInterviewPolicy::class);
        Gate::policy(RecruitmentInterviewScorecard::class, RecruitmentInterviewScorecardPolicy::class);
        Gate::policy(RecruitmentOfferLetter::class, RecruitmentOfferLetterPolicy::class);
        Gate::policy(RecruitmentHiring::class, RecruitmentHiringPolicy::class);
        Gate::policy(RecruitmentOnboardingCase::class, RecruitmentOnboardingCasePolicy::class);
        Gate::policy(Shift::class, ShiftPolicy::class);
        Gate::policy(CustomField::class, CustomFieldPolicy::class);
        Gate::policy(Language::class, LanguagePolicy::class);
        Gate::policy(Translation::class, TranslationPolicy::class);
        Gate::policy(TenancyModule::class, ModulePolicy::class);
        Gate::policy(Plan::class, PlanPolicy::class);
        Gate::policy(Tenant::class, TenantPolicy::class);
        Gate::policy(Warehouse::class, WarehousePolicy::class);
        Gate::policy(Item::class, ItemPolicy::class);
        Gate::policy(ItemCategory::class, ItemCategoryPolicy::class);
        Gate::policy(InventoryAttribute::class, InventoryAttributePolicy::class);
        Gate::policy(PurchaseOrder::class, PurchaseOrderPolicy::class);
        Gate::policy(SalesOrder::class, SalesOrderPolicy::class);
        Gate::policy(GoodsReceipt::class, GoodsReceiptPolicy::class);
        Gate::policy(SalesReturn::class, SalesReturnPolicy::class);
        Gate::policy(InventoryStockTransfer::class, InventoryStockTransferPolicy::class);
        Gate::policy(OperationalControlEvent::class, OperationalControlEventPolicy::class);

        $this->registerTenantAbilityGates();
        $this->registerCustomFieldPlanGate();
        $this->registerTenancyGates();
    }

    private function registerTenantAbilityGates(): void
    {
        foreach (config('tenant-permissions.abilities', []) as $slug) {
            Gate::define($slug, function (User $user, ...$args) use ($slug) {
                if ($user->isAdmin()) {
                    return true;
                }

                return app(TenantPermissionEvaluator::class)->allows($user, $slug, $args);
            });
        }
    }

    private function registerCustomFieldPlanGate(): void
    {
        Gate::define('custom_fields.plan', function (User $user): bool {
            if ($user->isAdmin()) {
                return true;
            }

            return app(CustomFieldsPlanService::class)->isEnabledForTenant($user->tenant);
        });
    }

    private function registerTenancyGates(): void
    {
        Gate::define('admin.access', fn (User $user) => $user->isAdmin());

        Gate::define('onboarding.manage', function (User $user): bool {
            if ($user->isAdmin()) {
                return false;
            }

            return $user->isTenantOwner();
        });

        Gate::define('modules.view', [ModulePolicy::class, 'viewAny']);
        Gate::define('modules.create', [ModulePolicy::class, 'create']);
        Gate::define('modules.update', [ModulePolicy::class, 'update']);
        Gate::define('modules.delete', [ModulePolicy::class, 'delete']);

        Gate::define('plans.view', [PlanPolicy::class, 'viewAny']);
        Gate::define('plans.create', [PlanPolicy::class, 'create']);
        Gate::define('plans.update', [PlanPolicy::class, 'update']);
        Gate::define('plans.delete', [PlanPolicy::class, 'delete']);

        Gate::define('tenants.view', [TenantPolicy::class, 'viewAny']);
        Gate::define('tenants.create', [TenantPolicy::class, 'create']);
        Gate::define('tenants.update', [TenantPolicy::class, 'update']);
        Gate::define('tenants.delete', [TenantPolicy::class, 'delete']);

        Gate::define('self_service.portal', function (User $user): bool {
            if ($user->isAdmin() || $user->tenant_id === null) {
                return false;
            }

            return $user->employee_id !== null;
        });

        Gate::define('dashboard.company', function (User $user): bool {
            if ($user->isAdmin() || $user->isTenantOwner()) {
                return true;
            }

            return app(TenantPermissionEvaluator::class)->hasAnyAbility($user);
        });

        Gate::define('accounting.hub', function (User $user): bool {
            if ($user->isAdmin() || $user->isTenantOwner()) {
                return true;
            }

            return $user->can('exports.access')
                || $user->can('payroll.view')
                || $user->can('operations.control.view');
        });

        Gate::define('self_service.team_attendance', function (User $user): bool {
            if ($user->isAdmin() || $user->tenant_id === null || $user->employee_id === null) {
                return false;
            }

            return app(EmployeeHierarchyService::class)
                ->managesAnyone((int) $user->tenant_id, (int) $user->employee_id);
        });
    }
}
