<?php

declare(strict_types=1);

namespace App\Http\Controllers\Helpers\Permissions;

use App\Enums\UserTypes;
use Hypervel\Http\Request;
use App\Models\User;
use Hypervel\Support\Facades\Auth;
use App\Enums\UserActions;


class UserPermissions
{
    use Roles;
    use PermissionsCheck;
    public static function IsParentofTargetUser(string|int $hashkeyORId)
    {
        $currentUser = Auth::user();
        if (!$currentUser) {
            return false;
        }
        if (is_numeric($hashkeyORId)) {
            $targetUser = User::find($hashkeyORId);
        } else {
            $targetUser = User::where('hashkey', $hashkeyORId)->first();
        }

        if (!$targetUser) {
            return false;
        }
        return $targetUser->parentuid === $currentUser->id;
    }

    /**
     * Check if the current user is an ancestor or part of the family of the target user.
     * The family includes both ancestors (parents, grandparents, etc.) and descendants.
     *
     * @param string|int $hashkeyORId - Target user's hashkey or ID
     * @return bool
     */
    public static function isAncestorOrFamilyOfTargetUser(string|int $hashkeyORId): bool
    {
        $currentUser = Auth::user();
        if (!$currentUser) {
            return false;
        }

        if (is_numeric($hashkeyORId)) {
            $targetUser = User::find($hashkeyORId);
        } else {
            $targetUser = User::where('hashkey', $hashkeyORId)->first();
        }

        if (!$targetUser) {
            return false;
        }
        if ($currentUser->id === $targetUser->id) {
            return true;
        }
        if ($targetUser->getAllDescendants()->contains($currentUser)) {
            return true;
        }
        $parent = $targetUser->parent;
        while ($parent) {
            if ($parent->id === $currentUser->id) {
                return true;
            }
            $parent = $parent->parent;
        }

        return false;
    }

    /**
     * Check if the current user is an indirect parent of the target user.
     * An indirect parent is someone who is an ancestor, but not a direct parent.
     *
     * @param string|int $hashkeyORId - Target user's hashkey or ID
     * @return bool
     */
    public static function isIndirectParentOfTargetUser(string|int $hashkeyORId): bool
    {
        $currentUser = Auth::user();
        if (!$currentUser) {
            return false;
        }

        if (is_numeric($hashkeyORId)) {
            $targetUser = User::find($hashkeyORId);
        } else {
            $targetUser = User::where('hashkey', $hashkeyORId)->first();
        }

        if (!$targetUser) {
            return false;
        }
        if ($currentUser->id === $targetUser->id) {
            return false;
        }
        $descendants = $targetUser->getAllDescendants();
        if ($descendants->contains($currentUser)) {
            if ($targetUser->parentuid === $currentUser->id) {
                return false;
            }
            return true;
        }
        return false;
    }
    private static function safeUserActionFromString(string $value): ?UserActions
    {
        foreach (UserActions::cases() as $case) {
            if ($case->value === $value) {
                return $case;
            }
        }

        return null;
    }

    public static function isDescendantOfCurrentUser(string|int|User|null $hashkeyOrId): bool
    {
        if (!$hashkeyOrId) {
            return false;
        }

        $currentUser = Auth::user();
        if (!$currentUser) {
            return false;
        }



        if ($hashkeyOrId instanceof User) {
            $targetUser = $hashkeyOrId;
        } else {
            $targetUser = is_numeric($hashkeyOrId)
                ? User::find($hashkeyOrId)
                : User::where('hashkey', $hashkeyOrId)->first();
        }



        if (!$targetUser || $currentUser->id === $targetUser->id) {
            return false;
        }


        $descendants = $currentUser->getAllDescendants();

        return $descendants->contains('id', $targetUser->id);
    }


    public static function isActionPermitted(string|int|UserTypes $hashkeyORId, UserActions $userActions)
    {

        $currentUser = Auth::user();
        if (!Auth::check()) {
            return false;
        }

        $currentUserType = $currentUser->acct_type;
        if (!($currentUserType instanceof UserTypes)) {
            $currentUserType = UserTypes::tryFrom($currentUserType) ?? UserTypes::PUBLIC;
        }

        $isDeniedRoles = self::isUserDeniedRoles($userActions);

        if ($isDeniedRoles) {
            return false;
        }

        //Started Changing this part, For actions that does not target a user
        if (self::CheckifRoleDoesNotRequireaTargetUser($userActions)) {
            $preliminary_permission = true;
        } elseif (($hashkeyORId || $hashkeyORId === 0 || $hashkeyORId === '0') && !($hashkeyORId instanceof UserTypes)) {
            $preliminary_permission = self::isUserPreliminaryPermissionAllowed($hashkeyORId);
        } elseif ($hashkeyORId instanceof UserTypes) {
            $preliminary_permission = self::isUserPreliminaryPermissionAllowed($hashkeyORId);
        } else {
            $preliminary_permission = false;
        }
        //end

        if (!$preliminary_permission) {
            return false;
        }
        $permissionString = $userActions->value;

        // if (isset(self::$roles[$currentUserType]) && in_array($permissionString, self::$roles[$currentUserType])) {
        //     return true;
        // } else {
        //     return false;
        // }

        $permissionEnum = self::safeUserActionFromString($permissionString);

        $allowedThroughAdditionalRoles = self::isUserAllowedbyAdditionalRoles($userActions);

        // if (isset(self::$roles[$currentUserType])) {
        //     file_put_contents('php://stderr',  print_r($currentUserType, true) . "\n");
        // }
        $isPermissionAllowed = (isset(self::roles()[$currentUserType->value]) &&
            in_array($permissionEnum, self::roles()[$currentUserType->value]));

        if (
            $permissionEnum && ($isPermissionAllowed ||
                $allowedThroughAdditionalRoles)
        ) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * Check if CurrentUser is Allowed to Modify Target User based on User type
     * @param string|int $hashkeyORId
     * @return bool
     */
    private static function isUserPreliminaryPermissionAllowed(string|int|UserTypes $hashkeyORId)
    {
        $currentUser = Auth::user();
        if (!$currentUser) {
            return false;
        }

        if ($currentUser->acct_type === UserTypes::ULTIMATE) {
            return true;
        }

        $currentUserType = $currentUser->acct_type;
        if (!($currentUserType instanceof UserTypes)) {
            $currentUserType = UserTypes::tryFrom($currentUserType) ?? UserTypes::PUBLIC;
        }
        $allowedUserTypes = UserTypeService::getAllowedUserTypes($currentUserType);




        //Updated This Part
        if ($hashkeyORId instanceof UserTypes) {
            $isTypeAllowedtobeModified = in_array($hashkeyORId, $allowedUserTypes);
        } else {

            try {
                if (is_string($hashkeyORId)) {
                    $TargetUser = User::where('hashkey', $hashkeyORId)->first();
                    $target_acct_type = $TargetUser->acct_type;
                } else {
                    $TargetUser = User::where('id', $hashkeyORId)->first();
                    $target_acct_type = $TargetUser->acct_type;
                }
                $isTypeAllowedtobeModified = in_array($target_acct_type, $allowedUserTypes);

            } catch (\Throwable $th) {
                throw new \Exception('' . $th->getMessage());
            }

        }
        //end



        $IndirectParent = self::isDescendantOfCurrentUser($hashkeyORId);
        $isSelf = $currentUser->hashkey === $hashkeyORId;

        return ($IndirectParent || $isSelf) && $isTypeAllowedtobeModified;


    }


    /**
     * Private function to check if Addional Roles is allowed way beyond the Roles of the User Type
     * @param \App\Enums\UserActions $userActions
     * @return bool
     */
    // private static function isUserAllowedbyAdditionalRoles(UserActions $userActions): bool
    // {
    //     $currentUser = User::findOrFail(Auth::id());
    //     if (!$currentUser) {
    //         return false;
    //     }

    //     $currentUserDeniedRoles = $currentUser->additional_roles ?? [];
    //     if (empty($currentUserDeniedRoles)) {
    //         return false;
    //     }
    //     if (in_array($userActions->value, $currentUserDeniedRoles)) {
    //         return true;
    //     } else {
    //         return false;
    //     }
    //     // 
    // }

    public static function isUserAllowedbyAdditionalRoles(UserActions $userActions): bool
    {
        $currentUser = Auth::user();
        if (!$currentUser)
            return false;

        $additionalRoles = $currentUser->additional_roles ?? [];
        if (empty($additionalRoles)) {
            return false;
        }

        foreach ($additionalRoles as $role) {
            if ($role instanceof UserActions) {
                if ($role === $userActions) {
                    return true;
                }
            } elseif (is_string($role)) {
                if ($role === $userActions->value) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Private function to check if A role is denied in the custom denied roles in user table
     * <b><i>TAKES PRECEDENCE OVER ANYTHING</b></i>
     * @param \App\Enums\UserActions $userActions
     * @return bool
     */
    public static function isUserDeniedRoles(UserActions $userActions)
    {
        $currentUser = User::findOrFail(Auth::id());
        if (!$currentUser) {
            return false;
        }

        if ($currentUser->acct_type === UserTypes::ULTIMATE) {
            return false;
        }

        $currentUserAdditionalRoles = $currentUser->denied_roles ?? [];
        if (empty($currentUserAdditionalRoles)) {
            return false;
        }
        if (in_array($userActions->value, $currentUserAdditionalRoles)) {
            return true;
        } else {
            return false;
        }
    }

    public static function getUserRoles(int $id)
    {
        try {
            $currentUser = User::findOrFail($id);
        } catch (\Throwable $th) {
            return false;
        }

        $acct_type = $currentUser->acct_type;

        $defaultuserRoles = self::roles()[$acct_type->value] ?? [];
        // if (!$defaultuserRoles) {
        //     return false;
        // }
        $additionalRoles = $currentUser->additional_roles ?? [];
        $deniedRoles = $currentUser->denied_roles ?? [];
        $mergedRoles = array_merge($defaultuserRoles, $additionalRoles);
        $uniqueRoles = [];
        foreach ($mergedRoles as $role) {
            $uniqueRoles[$role->value] = $role;
        }

        foreach ($deniedRoles as $denied) {
            unset($uniqueRoles[$denied->value]);
        }

        return array_values($uniqueRoles);

    }


    public static function normalizeRole(UserActions|string $role): UserActions
    {
        if ($role instanceof UserActions) {
            return $role;
        }

        // Try as backing value, e.g. "create_user"
        if ($e = UserActions::tryFrom($role)) {
            return $e;
        }

        // Try as CASE NAME, e.g. "CreateUser"
        foreach (UserActions::cases() as $case) {
            if ($case->name === $role) {
                return $case;
            }
        }

        // Try to convert PascalCase to snake_case and match: "CreateUser" -> "create_user"
        $snake = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $role));
        if ($e = UserActions::tryFrom($snake)) {
            return $e;
        }

        throw new \InvalidArgumentException("Unknown role: {$role}");
    }

    /**
     * Check if one user is an ancestor of another.
     */
    public static function isAncestorOf(User|int|string $ancestor, User|int|string $descendant): bool
    {
        if (!$ancestor || !$descendant) return false;

        $ancestorUser = $ancestor instanceof User ? $ancestor : (is_numeric($ancestor) ? User::find((int)$ancestor) : User::where('hashkey', $ancestor)->first());
        $descendantUser = $descendant instanceof User ? $descendant : (is_numeric($descendant) ? User::find((int)$descendant) : User::where('hashkey', $descendant)->first());

        if (!$ancestorUser || !$descendantUser) return false;

        if ($ancestorUser->id === $descendantUser->id) return true;

        $parent = $descendantUser->parent;
        while ($parent) {
            if ($parent->id === $ancestorUser->id) {
                return true;
            }
            $parent = $parent->parent;
        }

        return false;
    }

    /**
     * Check if a user is allowed to access a specific store.
     */
    public static function isUserAllowedAccessToStore(User|int|string $user, \App\Models\Market\Store|int|string $store): bool
    {
        $userObj = $user instanceof User ? $user : (is_numeric($user) ? User::find((int)$user) : User::where('hashkey', $user)->first());
        if (!$userObj) return false;

        if ($userObj->acct_type === UserTypes::ULTIMATE) return true;

        $storeObj = $store instanceof \App\Models\Market\Store ? $store : (is_numeric($store) ? \App\Models\Market\Store::find((int)$store) : \App\Models\Market\Store::where('hashkey', $store)->first());
        if (!$storeObj) return false;

        // Check if user owns or manages the store
        if ($userObj->id === $storeObj->owner_id || $userObj->id === $storeObj->manager_id) return true;

        // Check if user's parent is the owner/manager (for POS_TERMINAL/RIDER)
        if ($userObj->parentuid === $storeObj->owner_id || $userObj->parentuid === $storeObj->manager_id) return true;

        // check if user is an ancestor of the owner/manager
        if (self::isAncestorOf($userObj, $storeObj->owner_id) || self::isAncestorOf($userObj, $storeObj->manager_id)) return true;

        return false;
    }


}

trait PermissionsCheck
{

    /**
     * Check if the user modification is allowed based on the provided hashkey or ID.
     *
     * @param  string|int $hashkeyORId
     * @return bool
     */
    public static function isUserModificationAllowed(string|int $hashkeyORId): bool
    {
        return self::isActionPermitted($hashkeyORId, UserActions::ModifyUser);
    }

    /**
     * Check if the user can be set to active based on the provided hashkey or ID.
     *
     * @param  string|int $hashkeyORId
     * @return bool
     */
    public static function isUserSetActiveAllowed(string|int $hashkeyORId): bool
    {
        return self::isActionPermitted($hashkeyORId, UserActions::SetActiveUser);
    }

    /**
     * Check if the user can be set to inactive based on the provided hashkey or ID.
     *
     * @param  string|int $hashkeyORId
     * @return bool
     */
    public static function isUserSetInactiveAllowed(string|int $hashkeyORId): bool
    {
        return self::isActionPermitted($hashkeyORId, UserActions::SetInActiveUser);
    }

    /**
     * Check if the user can be deleted based on the provided hashkey or ID.
     *
     * @param  string|int $hashkeyORId
     * @return bool
     */
    public static function isUserDeletionAllowed(string|int $hashkeyORId): bool
    {
        return self::isActionPermitted($hashkeyORId, UserActions::DeleteUser);
    }

    public static function isUserExecChangeAllowed(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::UpdateUserExec);
    }

    public static function isUserExecViewingAllowed(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::ViewUserExec);
    }

    public static function isUserExecDeletionAllowed(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::DeleteUserExec);
    }


    public static function isUserNotesViewingAllowed(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::ViewUserNotes);
    }
    public static function isUserNotesUpdateAllowed(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::SetUserNotes);
    }
    public static function isUserNotesDeletionAllowed(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::DeleteUserNotes);
    }
    public static function isUserPasswordChangeAllowed(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::ChangeUserPassword);
    }
    public static function isDirectCreditTransfertoUserAllowed(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::DirectUserCreditTransfer);
    }
    public static function isForceLogoutUserAllowed(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::ForceLogoutUser);
    }

    public static function isUserAllowedtoViewAnotherUserRoles(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::UserAllowedtoChangeAnotherUserRoles);
    }

    public static function isUserAllowedtoViewSelfRoles(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::UserAllowedtoViewSelfRoles);
    }

    public static function isUserAllowedtoChangeAnotherUserRoles(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::UserAllowedtoChangeAnotherUserRoles);
    }

    public function isUserAllowedtoChangeParent(string|int $hashkeyORId)
    {
        return self::isActionPermitted($hashkeyORId, UserActions::ChangeAnotherUsersParent);
    }

}


trait Roles
{

    public static $RoleswithNoTargetUser = [
        UserActions::ViewAllUserTypes,
        UserActions::ListAllUsersAsParentforUserCreation,
        UserActions::CheckifMobileNumberExists,
        UserActions::CheckifUsernameExists,
        UserActions::ViewAllFiles,
        UserActions::UploadAllFiles,
        UserActions::DeleteAllFiles,
        UserActions::ModifyAllFiles,
        UserActions::DeleteAllStores,
        UserActions::DeleteAllProducts,
        UserActions::ViewAllFiles,
        UserActions::ViewGlobalReports,
        UserActions::AddProducttoAnyStore,
        UserActions::CreateAnnouncement,
        UserActions::ModifyAnnouncement,
        UserActions::DeleteAnnouncement,
        UserActions::ViewAllAnnouncements,
        UserActions::ViewFarmers,
        UserActions::VerifyFarmer,
        UserActions::CreateOrganization,
        UserActions::ViewOrganizations,
        UserActions::ViewShipments,
        UserActions::CreateShipment,
        UserActions::UpdateShipmentStatus,
        UserActions::CreateCourier,
        UserActions::ViewCouriers,
        UserActions::ViewGlobalTransactions,
        UserActions::CreateGlobalTransaction,
        UserActions::ViewAccountingReports,
        UserActions::ManageAccounting,
        UserActions::ViewProperties,
        UserActions::ViewReferrals,
        UserActions::ViewPosAccessKeys,
        UserActions::CreatePosAccessKey,
        UserActions::DeletePosAccessKey,
        UserActions::TogglePosAccessKey,
        UserActions::ViewPosReports,
        UserActions::ViewCustomers,
        UserActions::UltimateConsole,
        UserActions::UltimateLogs,
        UserActions::UltimateReports,
        UserActions::UltimateMaintenance,
        UserActions::UltimateQuery,
        UserActions::UltimateBatch,
        UserActions::UltimateGlobalMessage,
        UserActions::UltimateFlush,
        UserActions::ManageLandingPages,
        UserActions::JoinCooperative,
        UserActions::ManageQrphPaymentCode,
        UserActions::ViewChapterOrgChart,
        UserActions::ManageChapterMembers,
        UserActions::ViewScopedMemberReports,
        UserActions::AssignChapterOfficer,
    ];

    public static function CheckifRoleDoesNotRequireaTargetUser(UserActions $userAction): bool
    {
        return in_array($userAction, self::$RoleswithNoTargetUser, true);
    }

    // public static array $roles = [

    //     UserTypes::ULTIMATE->value => UserActions::cases(),
    //         // [
    //         //     UserActions::CreateUser,
    //         //     UserActions::ChangeUserPassword,
    //         //     UserActions::ModifyUser,
    //         //     UserActions::DeleteUser,
    //         //     UserActions::SetActiveUser,
    //         //     UserActions::SetInActiveUser,
    //         //     UserActions::DeveloperConsole,
    //         //     UserActions::UltimateConsole,
    //         //     UserActions::UltimateReports,
    //         //     UserActions::UltimateLogs,
    //         //     UserActions::UpdateSelfExec,
    //         //     UserActions::UpdateUserExec,
    //         //     UserActions::ViewUserExec,
    //         //     UserActions::ViewSelfExec,
    //         //     UserActions::SetUserNotes,
    //         //     UserActions::DeleteUserNotes,
    //         //     UserActions::ViewUserNotes,
    //         //     UserActions::SetSelfNotes,
    //         //     UserActions::DeleteSelfNotes,
    //         //     UserActions::ViewGlobalReports,
    //         //     UserActions::ModifyGlobalReports,
    //         //     UserActions::DeleteGlobalReports,
    //         //     UserActions::DeleteUserExec,
    //         //     UserActions::DirectUserCreditTransfer,
    //         // ],

    //     UserTypes::SUPER_OPERATOR->value => [
    //         UserActions::CreateUser,
    //         UserActions::ModifyUser,
    //         UserActions::SetActiveUser,
    //         UserActions::SetInActiveUser,
    //         UserActions::DeveloperConsole,
    //         UserActions::ViewGlobalReports,
    //     ],

    //     UserTypes::OPERATOR->value => [
    //         UserActions::CreateUser,
    //         UserActions::ModifyUser,
    //         UserActions::SetActiveUser,
    //         UserActions::SetInActiveUser,
    //     ],

    // ];

    public static function roles()
    {
        return [

            UserTypes::ULTIMATE->value => UserActions::cases(),

                // UserTypes::ULTIMATE->value =>
                //     [
                //         UserActions::CreateUser,
                //         UserActions::ChangeUserPassword,
                //         UserActions::ModifyUser,
                //         UserActions::DeleteUser,
                //         UserActions::SetActiveUser,
                //         UserActions::SetInActiveUser,
                //         UserActions::DeveloperConsole,
                //         UserActions::UltimateConsole,
                //         UserActions::UltimateReports,
                //         UserActions::UltimateLogs,
                //         UserActions::UpdateSelfExec,
                //         UserActions::UpdateUserExec,
                //         UserActions::ViewUserExec,
                //         UserActions::ViewSelfExec,
                //         UserActions::SetUserNotes,
                //         UserActions::DeleteUserNotes,
                //         UserActions::ViewUserNotes,
                //         UserActions::SetSelfNotes,
                //         UserActions::DeleteSelfNotes,
                //         UserActions::ViewGlobalReports,
                //         UserActions::ModifyGlobalReports,
                //         UserActions::DeleteGlobalReports,
                //         UserActions::DeleteUserExec,
                //         UserActions::DirectUserCreditTransfer,
                //         UserActions::UserAllowedtoViewOtherUserRoles,
                //         UserActions::UserAllowedtoViewAllRoles,
                //         UserActions::UserAllowedtoChangeAnotherUserRoles,
                //         UserActions::ChangeAnotherUsersParent,
                //         UserActions::ViewAllUserTypes,
                //         UserActions::ListAllUsersAsParentforUserCreation,
                //         UserActions::CheckifMobileNumberExists,
                //         UserActions::CheckifUsernameExists,
                //     ],

            UserTypes::SUPER_OPERATOR->value => [
                UserActions::CreateUserOperator,
                UserActions::CreateUserCoordinator,
                UserActions::CreateUserSupplierOverseer,
                UserActions::CreateUserWholesaleBuyer,
                UserActions::CreateUserSupplier,
                UserActions::CreateUserStoreOwner,
                UserActions::CreateUserStoreManager,
                UserActions::CreateUserUser,
                UserActions::CreateUserRider,
                UserActions::CreateUserPOSTerminal,
                UserActions::ModifyUser,
                UserActions::SetActiveUser,
                UserActions::SetInActiveUser,
                UserActions::DeveloperConsole,
                UserActions::ViewGlobalReports,
                UserActions::ViewFarmers,
                UserActions::ViewOrganizations,
                UserActions::ViewShipments,
                UserActions::CreateShipment,
                UserActions::UpdateShipmentStatus,
                UserActions::ViewCouriers,
                UserActions::ViewGlobalTransactions,
                UserActions::ViewAccountingReports,
                UserActions::ManageAccounting,
                UserActions::ViewProperties,
                UserActions::ViewReferrals,
                UserActions::ViewPosAccessKeys,
                UserActions::ViewPosReports,
                UserActions::ViewCustomers,
                UserActions::ViewAllUserTypes,
                UserActions::ListAllUsersAsParentforUserCreation,
                UserActions::CheckifMobileNumberExists,
                UserActions::CheckifUsernameExists,
                UserActions::ManageLandingPages,
                UserActions::JoinCooperative,
                UserActions::ViewAllStores,
                UserActions::CreateStoreGlobal,
                UserActions::ModifyAllStores,
                UserActions::ViewAllProducts,
                UserActions::CreateProductGlobal,
                UserActions::ModifyAllProducts,
                UserActions::AddProducttoAnyStore,
                UserActions::RemoveProductfromAnyStore,
                UserActions::CreatePosAccessKey,
                UserActions::DeletePosAccessKey,
                UserActions::TogglePosAccessKey,
                UserActions::SearchStockPhotos,
                UserActions::DownloadStockPhoto,
            ],

            UserTypes::OPERATOR->value => [
                UserActions::CreateUserCoordinator,
                UserActions::CreateUserSupplier,
                UserActions::CreateUserStoreOwner,
                UserActions::CreateUserRider,
                UserActions::CreateUserPOSTerminal,
                UserActions::ModifyUser,
                UserActions::SetActiveUser,
                UserActions::SetInActiveUser,
                UserActions::ViewShipments,
                UserActions::CreateShipment,
                UserActions::UpdateShipmentStatus,
                UserActions::ViewPosReports,
                UserActions::ViewCustomers,
                UserActions::ViewUserInfo,
                UserActions::ManageUserInfo,
                UserActions::JoinCooperative,
                UserActions::ViewOrganizations,
                UserActions::ViewFarmers,
                UserActions::ViewAllUserTypes,
                UserActions::ListAllUsersAsParentforUserCreation,
                UserActions::CheckifMobileNumberExists,
                UserActions::CheckifUsernameExists,
                UserActions::ManageLandingPages,
                UserActions::ViewAllStores,
                UserActions::CreateStoreGlobal,
                UserActions::ModifyAllStores,
                UserActions::ViewAllProducts,
                UserActions::CreateProductGlobal,
                UserActions::ModifyAllProducts,
                UserActions::AddProducttoAnyStore,
                UserActions::RemoveProductfromAnyStore,
                UserActions::ViewPosAccessKeys,
                UserActions::CreatePosAccessKey,
                UserActions::DeletePosAccessKey,
                UserActions::TogglePosAccessKey,
                UserActions::ViewAccountingReports,
                UserActions::ManageAccounting,
                UserActions::ViewProperties,
                UserActions::ViewReferrals,
                UserActions::SearchStockPhotos,
                UserActions::DownloadStockPhoto,
            ],

            UserTypes::USER->value => [
                UserActions::JoinCooperative,
                UserActions::ViewUserInfo,
                UserActions::ManageUserInfo,
            ],

            UserTypes::COOP_MEMBER->value => [
                UserActions::JoinCooperative,
                UserActions::ViewUserInfo,
                UserActions::ManageUserInfo,
                UserActions::ViewChapterOrgChart,
            ],

            UserTypes::COOP_OFFICER->value => [
                UserActions::JoinCooperative,
                UserActions::ViewUserInfo,
                UserActions::ManageUserInfo,
                UserActions::ViewOrganizations,
                UserActions::ViewChapterOrgChart,
                UserActions::ManageChapterMembers,
                UserActions::ViewScopedMemberReports,
                UserActions::AssignChapterOfficer,
                UserActions::ViewAccountingReports,
                UserActions::CheckifMobileNumberExists,
                UserActions::CheckifUsernameExists,
            ],

            UserTypes::COORDINATOR->value => [
                UserActions::ViewOrganizations,
                UserActions::ViewFarmers,
                UserActions::ViewShipments,
                UserActions::JoinCooperative,
                UserActions::ViewAccountingReports,
                UserActions::CreateUserSupplier,
                UserActions::CreateUserStoreManager,
                UserActions::CreateUserRider,
                UserActions::ViewAllUserTypes,
                UserActions::ListAllUsersAsParentforUserCreation,
                UserActions::CheckifMobileNumberExists,
                UserActions::CheckifUsernameExists,
                UserActions::ManageLandingPages,
            ],

            UserTypes::STORE_OWNER->value => [
                UserActions::CreateUserStoreManager,
                UserActions::CreateUserRider,
                UserActions::CreateUserPOSTerminal,
                UserActions::ViewUserInfo,
                UserActions::ManageUserInfo,
                UserActions::ViewShipments,
                UserActions::ViewPosReports,
                UserActions::ViewPosAccessKeys,
                UserActions::CreatePosAccessKey,
                UserActions::DeletePosAccessKey,
                UserActions::TogglePosAccessKey,
                UserActions::JoinCooperative,
                UserActions::ViewAccountingReports,
                UserActions::ManageAccounting,
                UserActions::ViewGlobalReports,
                UserActions::ViewGlobalTransactions,
                UserActions::SearchStockPhotos,
                UserActions::DownloadStockPhoto,
            ],

            UserTypes::STORE_MANAGER->value => [
                UserActions::CreateUserRider,
                UserActions::CreateUserPOSTerminal,
                UserActions::ViewUserInfo,
                UserActions::ManageUserInfo,
                UserActions::ViewShipments,
                UserActions::ViewPosReports,
                UserActions::ViewPosAccessKeys,
                UserActions::CreatePosAccessKey,
                UserActions::DeletePosAccessKey,
                UserActions::TogglePosAccessKey,
                UserActions::JoinCooperative,
                UserActions::ViewAccountingReports,
                UserActions::ManageAccounting,
                UserActions::ViewGlobalReports,
                UserActions::ViewGlobalTransactions,
                UserActions::CreateProductForOwnStore,
                UserActions::AddProducttoOwnStore,
                UserActions::SearchStockPhotos,
                UserActions::DownloadStockPhoto,
            ],

            UserTypes::SUPPLIER_OVERSEER->value => [
                UserActions::CreateUserSupplier,
                UserActions::CreateUserWholesaleBuyer,
                UserActions::CreateUserRider,
                UserActions::ViewUserInfo,
                UserActions::ManageUserInfo,
            ],

            UserTypes::SUPPLIER->value => [
                UserActions::CreateUserRider,
                UserActions::ViewUserInfo,
                UserActions::ManageUserInfo,
                UserActions::JoinCooperative,
            ],

            UserTypes::RIDER->value => [
                UserActions::ViewShipments,
                UserActions::UpdateShipmentStatus,
                UserActions::ViewUserInfo,
                UserActions::ManageUserInfo,
            ],

            UserTypes::POS_TERMINAL->value => [
                UserActions::ViewPosReports,
                UserActions::ViewCustomers,
                UserActions::ViewUserInfo,
                UserActions::ManageUserInfo,
                UserActions::ViewShipments,
            ],

            UserTypes::AUDIT->value => [
                UserActions::ViewGlobalReports,
                UserActions::ViewAllStores,
                UserActions::ViewAllProducts,
                UserActions::ViewAllAnnouncements,
                UserActions::ViewFarmers,
                UserActions::ViewOrganizations,
                UserActions::ViewShipments,
                UserActions::ViewCouriers,
                UserActions::ViewGlobalTransactions,
                UserActions::ViewAccountingReports,
                UserActions::ViewProperties,
                UserActions::ViewReferrals,
                UserActions::ViewPosAccessKeys,
                UserActions::ViewPosReports,
                UserActions::ViewCustomers,
                UserActions::ViewAllUserTypes,
                UserActions::CheckifMobileNumberExists,
                UserActions::CheckifUsernameExists,
            ],

        ];
    }
}

class UserTypeService
{
    public static function getAllowedUserTypes(UserTypes $currentUserType): array
    {
        return match ($currentUserType) {
            UserTypes::ULTIMATE => UserTypes::cases(),

            UserTypes::SUPER_OPERATOR => [
                UserTypes::OPERATOR,
                UserTypes::COORDINATOR,
                UserTypes::COOP_OFFICER,
                UserTypes::COOP_MEMBER,
                UserTypes::ANY_USER,
                UserTypes::SUPPLIER,
                UserTypes::STORE_OWNER,
                UserTypes::STORE_MANAGER,
                UserTypes::SUPPLIER_OVERSEER,
                UserTypes::WHOLESALE_BUYER,
                UserTypes::RIDER,
                UserTypes::POS_TERMINAL,
            ],

            UserTypes::OPERATOR => [
                UserTypes::COORDINATOR,
                UserTypes::COOP_OFFICER,
                UserTypes::COOP_MEMBER,
                UserTypes::SUPPLIER,
                UserTypes::STORE_OWNER,
                UserTypes::RIDER,
                UserTypes::POS_TERMINAL,
            ],

            UserTypes::COORDINATOR => [
                UserTypes::COOP_OFFICER,
                UserTypes::COOP_MEMBER,
                UserTypes::SUPPLIER,
                UserTypes::STORE_MANAGER,
                UserTypes::RIDER,
            ],

            UserTypes::COOP_OFFICER => [
                UserTypes::COOP_MEMBER,
            ],

            UserTypes::STORE_OWNER => [
                UserTypes::STORE_MANAGER,
                UserTypes::RIDER,
                UserTypes::POS_TERMINAL,
            ],

            UserTypes::STORE_MANAGER => [
                UserTypes::RIDER,
                UserTypes::POS_TERMINAL,
            ],

            UserTypes::SUPPLIER => [
                UserTypes::RIDER,
            ],

            UserTypes::SUPPLIER_OVERSEER => [
                UserTypes::SUPPLIER,
                UserTypes::WHOLESALE_BUYER,
                UserTypes::RIDER,
            ],

            default => [],
        };
    }
}
