<?php

declare(strict_types=1);

/**
 * ACC ACL / Auth Compatibility Layer
 */

$GLOBALS['acc_current_user'] = null;

/* ── JWT helpers (standalone) ────────────────────────────── */

function _acc_jwt_secret(): string
{
    return defined('ACC_JWT_SECRET') ? ACC_JWT_SECRET : '6f9a2b8c4d1e7f3a5b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f';
}

function _acc_jwt_b64_decode(string $data): string
{
    return base64_decode(strtr($data, '-_', '+/') . str_repeat('=', 3 - (3 + strlen($data)) % 4));
}

function _acc_jwt_b64_encode(string $data): string
{
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

/**
 * توکن JWT را اعتبارسنجی کرده و payload را برمی‌گرداند (یا false در صورت خطا)
 */
function _acc_jwt_validate(string $token)
{
    $parts = explode('.', $token);
    if (count($parts) !== 3) return false;

    [$header, $payload, $signature] = $parts;

    $expected = hash_hmac('sha256', "{$header}.{$payload}", _acc_jwt_secret(), true);
    if (!hash_equals(_acc_jwt_b64_encode($expected), $signature)) return false;

    $data = json_decode(_acc_jwt_b64_decode($payload), true);
    if (!$data) return false;

    if (isset($data['exp']) && time() > (int)$data['exp']) return false;

    return $data;
}

/**
 * Authorization header درخواست (در صورت وجود)
 */
function _acc_request_authorization_header(): string
{
    if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
        return trim((string) $_SERVER['HTTP_AUTHORIZATION']);
    }
    if (!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
        return trim((string) $_SERVER['REDIRECT_HTTP_AUTHORIZATION']);
    }
    if (function_exists('apache_request_headers')) {
        foreach (apache_request_headers() as $k => $v) {
            if (strtolower((string) $k) === 'authorization') {
                return trim((string) $v);
            }
        }
    }
    return '';
}

/**
 * آیا کلاینت Bearer token فرستاده (حتی اگر نامعتبر باشد)؟
 */
function _acc_auth_header_has_bearer(): bool
{
    return (bool) preg_match('/Bearer\s+\S+/i', _acc_request_authorization_header());
}

/**
 * user_id را از Authorization header استخراج می‌کند
 */
function _acc_jwt_user_id_from_request(): int
{
    $auth = _acc_request_authorization_header();
    if (!$auth || !preg_match('/Bearer\s(\S+)/i', $auth, $m)) {
        return 0;
    }

    $data = _acc_jwt_validate($m[1]);
    return ($data && isset($data['sub'])) ? (int) $data['sub'] : 0;
}

/**
 * نقش‌ها و مجوزهای واقعی ACL کاربر را از DB بارگذاری می‌کند
 */
function _acc_load_user_acl_profile(int $user_id, array $base): array
{
    $roles       = ['authenticated'];
    $permissions = [];

    if ($user_id > 0 && function_exists('acl_get_user_roles')) {
        $db_roles = acl_get_user_roles($user_id);
        $slugs    = array_values(array_filter(array_map(
            static fn(array $r): string => (string) ($r['slug'] ?? ''),
            $db_roles ?: []
        )));
        if ($slugs) {
            $roles = $slugs;
        }
    }

    if ($user_id > 0 && function_exists('acl_get_user_permissions')) {
        $db_perms = acl_get_user_permissions($user_id);
        foreach ($db_perms ?: [] as $perm) {
            if (is_array($perm)) {
                $key = (string) ($perm['key'] ?? $perm['permission_key'] ?? '');
                if ($key !== '') {
                    $permissions[] = $key;
                }
                continue;
            }
            if (is_string($perm) && $perm !== '') {
                $permissions[] = $perm;
            }
        }
        $permissions = array_values(array_unique($permissions));
    }

    if ($user_id > 0 && function_exists('acl_user_is_super_admin') && acl_user_is_super_admin($user_id)) {
        $permissions[] = '*';
        $permissions   = array_values(array_unique($permissions));
    }

    $base['roles']       = $roles;
    $base['permissions'] = $permissions;

    return $base;
}

/**
 * گرفتن کاربر فعلی — اول JWT را چک می‌کند، بعد mock
 */
function acc_get_current_user(): ?array
{
    if ($GLOBALS['acc_current_user'] !== null) {
        return $GLOBALS['acc_current_user'];
    }

    // ── ابتدا JWT token از Authorization header ──────────────────
    $jwt_user_id = _acc_jwt_user_id_from_request();

    if ($jwt_user_id > 0) {
        // user_id از JWT معتبر است؛ اطلاعات کاربر را از DB بخوان
        global $wpdb;
        $user = null;
        if (isset($wpdb)) {
            try {
                $row = $wpdb->get_row(
                    $wpdb->prepare("SELECT ID, user_login, display_name FROM {$wpdb->users} WHERE ID = %d LIMIT 1", $jwt_user_id),
                    ARRAY_A
                );
                if ($row) {
                    $user = _acc_load_user_acl_profile($jwt_user_id, [
                        'id'           => (int) $row['ID'],
                        'username'     => $row['user_login'],
                        'display_name' => $row['display_name'],
                    ]);
                }
            } catch (\Throwable $e) {
                // در صورت خطا fallback
            }
        }
        // اگر DB query موفق نبود، با همان ID ادامه بده (بدون wildcard)
        if (!$user) {
            $user = _acc_load_user_acl_profile($jwt_user_id, [
                'id'           => $jwt_user_id,
                'username'     => 'user_' . $jwt_user_id,
                'display_name' => '',
            ]);
        }
        $GLOBALS['acc_current_user'] = $user;
        // برای توابعی که $GLOBALS['acc_jwt_user_id'] را می‌خوانند
        $GLOBALS['acc_jwt_user_id'] = $jwt_user_id;
        return $user;
    }

    // ── در حالت mock (توسعه) فقط وقتی هیچ Bearer token ارسال نشده ─
    // اگر توکن نامعتبر/منقضی فرستاده شده، به mock-admin برنگرد (جلوگیری از bypass محدوده)
    if (
        defined('ACC_AUTH_MODE') && ACC_AUTH_MODE === 'mock'
        && ! _acc_auth_header_has_bearer()
    ) {
        $mock_id = defined('ACC_MOCK_USER_ID') ? (int) ACC_MOCK_USER_ID : 1;
        $GLOBALS['acc_current_user'] = _acc_load_user_acl_profile($mock_id, [
            'id'           => $mock_id,
            'username'     => 'mock-admin',
            'display_name' => 'Mock Admin',
        ]);
        return $GLOBALS['acc_current_user'];
    }

    $GLOBALS['acc_current_user'] = null;
    return null;
}

function get_current_user_id(): int
{
    $user = acc_get_current_user();

    return $user ? (int) $user['id'] : 0;
}

function wp_get_current_user()
{
    $user = acc_get_current_user();

    if (!$user) {
        return (object) [
            'ID' => 0,
            'user_login' => '',
            'roles' => [],
        ];
    }

    return (object) [
        'ID'         => $user['id'],
        'user_login' => $user['username'] ?? '',
        'roles'      => $user['roles'] ?? [],
    ];
}

function is_user_logged_in(): bool
{
    return get_current_user_id() > 0;
}

/**
 * permission_callback عمومی برای Routeها
 * اول JWT را چک می‌کند؛ در حالت mock بدون توکن هم اجازه می‌دهد
 */
function acc_jwt_check_permission($request = null): bool
{
    // اگر توکن معتبر در header باشد → قبول
    $jwt_uid = _acc_jwt_user_id_from_request();
    if ($jwt_uid > 0) {
        $GLOBALS['acc_jwt_user_id'] = $jwt_uid;
        return true;
    }

    // توکن نامعتبر/منقضی نباید به mock-admin دسترسی بدهد
    if (_acc_auth_header_has_bearer()) {
        return false;
    }

    // mock فقط با ACC_ENABLE_MOCK_AUTH=1 و محیط محلی
    if (
        defined('ACC_AUTH_MODE') && ACC_AUTH_MODE === 'mock'
        && getenv('ACC_ENABLE_MOCK_AUTH') === '1'
        && function_exists('acc_is_local_environment')
        && acc_is_local_environment()
    ) {
        return true;
    }

    return false;
}

/**
 * current_user_can compatibility
 */
if ( ! function_exists( 'current_user_can' ) ) {
    function current_user_can(string $capability, ...$args): bool
    {
        return acl_can($capability);
    }
}

/**
 * ACL permission check — fallback ساده اگر acl-functions لود نشده
 */
if ( ! function_exists( 'acl_can' ) ) {
    function acl_can(string $permission, ?string $scope_type = null, ?int $scope_id = null): bool
    {
        $user = acc_get_current_user();

        if (!$user) {
            return false;
        }

        $permissions = $user['permissions'] ?? [];

        if (in_array('*', $permissions, true)) {
            return true;
        }

        if (in_array($permission, $permissions, true)) {
            return true;
        }

        foreach ($permissions as $perm) {
            if (str_ends_with($perm, '.*')) {
                $prefix = substr($perm, 0, -2);

                if (str_starts_with($permission, $prefix . '.')) {
                    return true;
                }
            }
        }

        return false;
    }
}

if ( ! function_exists( 'acl_get_user_permissions' ) ) {
    function acl_get_user_permissions(int $user_id): array
    {
        $user = acc_get_current_user();

        if (!$user || (int) $user['id'] !== $user_id) {
            return [];
        }

        return $user['permissions'] ?? [];
    }
}

if ( ! function_exists( 'acl_get_user_roles' ) ) {
    function acl_get_user_roles(int $user_id): array
    {
        $user = acc_get_current_user();

        if (!$user || (int) $user['id'] !== $user_id) {
            return [];
        }

        return $user['roles'] ?? [];
    }
}

if ( ! function_exists( 'acl_get_user_menus' ) ) {
    function acl_get_user_menus(int $user_id): array
    {
        return [];
    }
}

/**
 * PHP 7 compatibility for str_starts_with / str_ends_with
 * اگر PHP شما 8 است، مشکلی نیست.
 */
if (!function_exists('str_starts_with')) {
    function str_starts_with(string $haystack, string $needle): bool
    {
        return $needle === '' || strpos($haystack, $needle) === 0;
    }
}

if (!function_exists('str_ends_with')) {
    function str_ends_with(string $haystack, string $needle): bool
    {
        if ($needle === '') {
            return true;
        }

        return substr($haystack, -strlen($needle)) === $needle;
    }
}
