<?php

namespace App\Services\Moderation;

use App\Enums\ModerationStatus;
use App\Models\ContentModerationFinding;
use App\Models\User;

class UserRiskScoreService
{
    /**
     * @param array<int, string> $domains
     * @return array{risk_score:int,score_modifier:int,signals:array<string, int>}
     */
    public function assess(?int $userId, array $domains = []): array
    {
        if (! $userId) {
            return ['risk_score' => 0, 'score_modifier' => 0, 'signals' => []];
        }

        $user = User::query()->with('statistics:user_id,uploads_count')->find($userId);
        if (! $user) {
            return ['risk_score' => 0, 'score_modifier' => 0, 'signals' => []];
        }

        $summary = ContentModerationFinding::query()
            ->where('user_id', $userId)
            ->selectRaw('COUNT(*) as total_findings')
            ->selectRaw("SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as confirmed_spam_count", [ModerationStatus::ConfirmedSpam->value])
            ->selectRaw("SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as safe_count", [ModerationStatus::ReviewedSafe->value])
            ->selectRaw("SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as pending_count", [ModerationStatus::Pending->value])
            ->first();

        $confirmedSpam = (int) ($summary?->confirmed_spam_count ?? 0);
        $safeCount = (int) ($summary?->safe_count ?? 0);
        $pendingCount = (int) ($summary?->pending_count ?? 0);
        $domainRepeatCount = ContentModerationFinding::query()
            ->where('user_id', $userId)
            ->whereNotNull('matched_domains_json')
            ->get(['matched_domains_json'])
            ->reduce(function (int $carry, ContentModerationFinding $finding) use ($domains): int {
                return $carry + (empty(array_intersect((array) $finding->matched_domains_json, $domains)) ? 0 : 1);
            }, 0);

        $accountAgeDays = max(0, \now()->diffInDays($user->created_at));
        $uploadsCount = (int) ($user->statistics?->uploads_count ?? 0);

        $riskScore = 0;
        $riskScore += $confirmedSpam * 18;
        $riskScore += $pendingCount * 5;
        $riskScore += min(20, $domainRepeatCount * 6);
        $riskScore -= min(18, $safeCount * 4);
        $riskScore -= $accountAgeDays >= 365 ? 8 : ($accountAgeDays >= 90 ? 4 : 0);
        $riskScore -= $uploadsCount >= 25 ? 6 : ($uploadsCount >= 10 ? 3 : 0);
        $riskScore = max(0, min(100, $riskScore));

        $modifier = 0;
        if ($riskScore >= 75) {
            $modifier = (int) \app('config')->get('content_moderation.user_risk.high_modifier', 18);
        } elseif ($riskScore >= 50) {
            $modifier = (int) \app('config')->get('content_moderation.user_risk.medium_modifier', 10);
        } elseif ($riskScore >= 25) {
            $modifier = (int) \app('config')->get('content_moderation.user_risk.low_modifier', 4);
        } elseif ($riskScore <= 5 && $accountAgeDays >= 180 && $uploadsCount >= 10) {
            $modifier = (int) \app('config')->get('content_moderation.user_risk.trusted_modifier', -6);
        } elseif ($riskScore <= 12 && $safeCount >= 2) {
            $modifier = -3;
        }

        return [
            'risk_score' => $riskScore,
            'score_modifier' => $modifier,
            'signals' => [
                'confirmed_spam_count' => $confirmedSpam,
                'safe_count' => $safeCount,
                'pending_count' => $pendingCount,
                'domain_repeat_count' => $domainRepeatCount,
                'account_age_days' => $accountAgeDays,
                'uploads_count' => $uploadsCount,
            ],
        ];
    }
}