<?php

namespace App\Support;

use App\Models\ActivationRequest;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;

class AdminActivityLogSupport
{
    private const MASKED_VALUE = '[HIDDEN]';

    private const SENSITIVE_KEY_PARTS = [
        'password',
        'passcode',
        'passphrase',
        'pin',
        'otp',
        'token',
        'secret',
        'apikey',
        'privatekey',
        'authorization',
        'signature',
    ];

    /**
     * @param  array<string, mixed>  $payload
     * @return array<string, mixed>
     */
    public static function sanitizePayload(array $payload): array
    {
        $clean = [];

        foreach ($payload as $key => $value) {
            if (!is_string($key) || $key === '') {
                continue;
            }

            $clean[$key] = self::sanitizeValue($value, $key);
        }

        return $clean;
    }

    /**
     * @return array<string, mixed>
     */
    public static function buildRequestPayload(Request $request): array
    {
        $payload = self::sanitizePayload(
            $request->except(array_keys($request->allFiles()))
        );

        $routeContext = self::routeContext($request);
        if ($routeContext !== []) {
            $payload['__route_context'] = $routeContext;
        }

        $subjectContext = self::subjectContext($request);
        if ($subjectContext !== []) {
            $payload['__subject'] = $subjectContext;
        }

        return $payload;
    }

    public static function isSensitiveKey(?string $key): bool
    {
        $normalized = strtolower((string) $key);
        if ($normalized === '') {
            return false;
        }

        $normalized = preg_replace('/[^a-z0-9]/', '', $normalized) ?: '';
        if ($normalized === '') {
            return false;
        }

        foreach (self::SENSITIVE_KEY_PARTS as $part) {
            if (str_contains($normalized, $part)) {
                return true;
            }
        }

        return false;
    }

    private static function sanitizeValue(mixed $value, ?string $key = null): mixed
    {
        if (self::isSensitiveKey($key)) {
            return self::MASKED_VALUE;
        }

        if (is_array($value)) {
            $items = [];
            $count = 0;

            foreach ($value as $childKey => $item) {
                if ($count >= 20) {
                    $items['__truncated__'] = 'More items hidden';
                    break;
                }

                $normalizedChildKey = is_int($childKey) ? $childKey : (string) $childKey;
                $items[$normalizedChildKey] = self::sanitizeValue(
                    $item,
                    is_int($childKey) ? $key : (string) $childKey
                );
                $count++;
            }

            return $items;
        }

        if (is_bool($value) || is_int($value) || is_float($value) || $value === null) {
            return $value;
        }

        return Str::limit(trim((string) $value), 500, '');
    }

    /**
     * @return array<string, mixed>
     */
    private static function routeContext(Request $request): array
    {
        $route = $request->route();
        if (!$route) {
            return [];
        }

        $context = [];

        foreach ($route->parametersWithoutNulls() as $key => $value) {
            if ($value instanceof User) {
                $context[$key] = self::userSnapshot($value);
                continue;
            }

            if ($value instanceof ActivationRequest) {
                $context[$key] = self::activationRequestSnapshot($value);
                continue;
            }

            if ($value instanceof Model) {
                $context[$key] = [
                    'model' => class_basename($value),
                    'id' => (int) ($value->getKey() ?? 0),
                ];
                continue;
            }

            if (is_scalar($value) || $value === null) {
                $context[(string) $key] = self::sanitizeValue($value, (string) $key);
            }
        }

        return $context;
    }

    /**
     * @return array<string, mixed>
     */
    private static function subjectContext(Request $request): array
    {
        $context = [];

        $activationRequest = self::resolveActivationRequest($request);
        $user = self::resolveUser($request, $activationRequest);

        if ($user) {
            $context['user'] = self::userSnapshot($user);
        }

        if ($activationRequest) {
            $context['activation_request'] = self::activationRequestSnapshot($activationRequest);
        }

        $verification = self::verificationContext($request);
        if ($verification !== []) {
            $context['verification'] = $verification;
        }

        return $context;
    }

    /**
     * @return array<string, mixed>
     */
    private static function verificationContext(Request $request): array
    {
        $pairs = [
            'action' => $request->input('action'),
            'commission_mode' => $request->input('commission_mode'),
            'transaction_reference' => $request->input('transaction_reference'),
            'typing_job_mode' => $request->input('typing_job_mode'),
            'welcome_offer_mode' => $request->input('welcome_offer_mode'),
            'leadership_count_mode' => $request->input('leadership_count_mode'),
            'typing_job_unverify_mode' => $request->input('typing_job_unverify_mode'),
            'welcome_offer_unverify_mode' => $request->input('welcome_offer_unverify_mode'),
            'leadership_unverify_mode' => $request->input('leadership_unverify_mode'),
        ];

        $context = [];

        foreach ($pairs as $key => $value) {
            if ($value === null || $value === '') {
                continue;
            }

            $context[$key] = self::sanitizeValue($value, $key);
        }

        return $context;
    }

    private static function resolveUser(Request $request, ?ActivationRequest $activationRequest): ?User
    {
        $route = $request->route();

        if ($route) {
            $routeUser = $route->parameter('user');
            if ($routeUser instanceof User) {
                return $routeUser;
            }

            $routeName = (string) $route->getName();
            if (str_starts_with($routeName, 'admin.users.')) {
                $routeId = (int) $route->parameter('id', 0);
                if ($routeId > 0) {
                    return self::findUser($routeId);
                }
            }
        }

        $userId = (int) $request->input('user_id', 0);
        if ($userId > 0) {
            return self::findUser($userId);
        }

        if ($activationRequest && (int) ($activationRequest->user_id ?? 0) > 0) {
            return $activationRequest->relationLoaded('user')
                ? $activationRequest->user
                : self::findUser((int) $activationRequest->user_id);
        }

        return null;
    }

    private static function resolveActivationRequest(Request $request): ?ActivationRequest
    {
        $route = $request->route();
        if ($route) {
            $routeRequest = $route->parameter('activationRequest');
            if ($routeRequest instanceof ActivationRequest) {
                return $routeRequest;
            }
        }

        $requestId = (int) $request->input('activation_request_id', 0);
        if ($requestId > 0) {
            return self::findActivationRequest($requestId);
        }

        return null;
    }

    private static function findUser(int $userId): ?User
    {
        if ($userId <= 0 || !Schema::hasTable('users')) {
            return null;
        }

        return User::query()->find($userId, [
            'id',
            'name',
            'email',
            'mobile',
            'referral_code',
            'referred_by',
            'is_active',
        ]);
    }

    private static function findActivationRequest(int $requestId): ?ActivationRequest
    {
        if ($requestId <= 0 || !Schema::hasTable('activation_requests')) {
            return null;
        }

        return ActivationRequest::query()->find($requestId, [
            'id',
            'user_id',
            'mobile',
            'referral_code',
            'status',
            'reviewed_by',
            'reviewed_at',
        ]);
    }

    /**
     * @return array<string, mixed>
     */
    private static function userSnapshot(User $user): array
    {
        return [
            'id' => (int) $user->id,
            'name' => (string) ($user->name ?? ''),
            'email' => (string) ($user->email ?? ''),
            'mobile' => (string) ($user->mobile ?? ''),
            'referral_code' => (string) ($user->referral_code ?? ''),
            'referred_by' => (string) ($user->referred_by ?? ''),
            'is_active' => (int) ($user->is_active ?? 0),
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private static function activationRequestSnapshot(ActivationRequest $activationRequest): array
    {
        return [
            'id' => (int) $activationRequest->id,
            'user_id' => (int) ($activationRequest->user_id ?? 0),
            'mobile' => (string) ($activationRequest->mobile ?? ''),
            'referral_code' => (string) ($activationRequest->referral_code ?? ''),
            'status' => (string) ($activationRequest->status ?? ''),
            'reviewed_by' => (int) ($activationRequest->reviewed_by ?? 0),
        ];
    }
}
