<?php

namespace App\Services;

use App\Models\FraudLog;
use App\Models\User;
use App\Models\UserKyc;
use Illuminate\Http\Request;

class FraudDetectionService
{
    /**
     * @param array<string,mixed> $context
     */
    public function logIfSuspicious(User $user, array $context = []): void
    {
        $ip = (string) ($context['ip_address'] ?? request()->ip());
        $device = (string) ($context['device'] ?? request()->userAgent());

        $this->detectSharedIp($user, $ip, $device);
        $this->detectDuplicateKyc($user, $ip, $device);
    }

    public function logDeviceLogin(User $user, Request $request): void
    {
        $deviceId = (string) $request->header('X-Device-Id', '');
        $sameDeviceUsers = User::query()
            ->where('id', '!=', $user->id)
            ->whereHas('devices', function ($query) use ($deviceId): void {
                $query->where('device_id', $deviceId);
            })
            ->count();

        if ($deviceId !== '' && $sameDeviceUsers >= 1) {
            $this->log($user->id, 'multiple_device_logins', [
                'device_id' => $deviceId,
                'linked_users' => $sameDeviceUsers,
            ], $request->ip(), (string) $request->userAgent());
        }
    }

    private function detectSharedIp(User $user, string $ip, string $device): void
    {
        if ($ip === '') {
            return;
        }

        $count = (int) User::query()
            ->where('id', '!=', $user->id)
            ->whereHas('ipLogs', fn ($query) => $query->where('ip_address', $ip))
            ->count();

        if ($count >= (int) setting('fraud_same_ip_threshold', 3)) {
            $this->log($user->id, 'same_ip_multiple_accounts', [
                'ip' => $ip,
                'other_accounts' => $count,
            ], $ip, $device);
        }
    }

    private function detectDuplicateKyc(User $user, string $ip, string $device): void
    {
        $kyc = UserKyc::query()->where('user_id', $user->id)->first();
        if (! $kyc) {
            return;
        }

        if ($kyc->pan_number) {
            $dupPan = UserKyc::query()
                ->where('user_id', '!=', $user->id)
                ->where('pan_number', $kyc->pan_number)
                ->count();
            if ($dupPan > 0) {
                $this->log($user->id, 'duplicate_kyc_pan', ['pan' => $kyc->pan_number, 'duplicates' => $dupPan], $ip, $device);
            }
        }

        if ($kyc->bank_account_number) {
            $dupBank = UserKyc::query()
                ->where('user_id', '!=', $user->id)
                ->where('bank_account_number', $kyc->bank_account_number)
                ->count();
            if ($dupBank > 0) {
                $this->log($user->id, 'duplicate_bank_account', ['bank_account' => $kyc->bank_account_number, 'duplicates' => $dupBank], $ip, $device);
            }
        }
    }

    /**
     * @param array<string,mixed> $data
     */
    private function log(int $userId, string $type, array $data, ?string $ip, ?string $device): void
    {
        FraudLog::query()->create([
            'user_id' => $userId,
            'type' => $type,
            'data' => $data,
            'ip_address' => $ip,
            'device' => $device,
        ]);
    }
}
