<?php

declare(strict_types=1);

namespace Kylin\RiskControl\Services;

use Illuminate\Support\Facades\Log;

/**
 * 可疑交易报告服务
 *
 * 依据《金融机构大额交易和可疑交易报告管理办法》：
 * 可疑交易需人工审核后上报。
 *
 * 可疑交易特征：
 *  - 短期内资金分散转入、集中转出
 *  - 资金收付频率及金额与企业经营规模明显不符
 *  - 资金收付流向与企业经营范围明显不符
 *  - 长期闲置的账户突然启用且发生大量资金收付
 *
 * 使用方式：
 *   $result = SuspiciousTransactionReport::analyze($transaction);
 *   $result = SuspiciousTransactionReport::isSuspicious($transaction);
 */
final class SuspiciousTransactionReport
{
    /** 可疑交易特征 */
    public const PATTERN_SCATTER_IN_CONCENTRATE_OUT = 'scatter_in_concentrate_out';
    public const PATTERN_AMOUNT_MISMATCH = 'amount_mismatch';
    public const PATTERN_FLOW_MISMATCH = 'flow_mismatch';
    public const PATTERN_DORMANT_SUDDEN_ACTIVE = 'dormant_sudden_active';

    /** 可疑特征阈值 */
    public const SCATTER_IN_COUNT = 5;       // 分散转入 5 笔以上
    public const DORMANT_DAYS = 180;         // 闲置 180 天后突然启用
    public const SUDDEN_ACTIVE_AMOUNT = 100_000; // 突然启用发生大额交易

    /**
     * 分析交易是否可疑
     *
     * @param array $transaction 交易数据
     * @return array{ suspicious: bool, risk_level: string, patterns: array, review_required: bool }
     */
    public static function analyze(array $transaction): array
    {
        $patterns = [];

        // 检测分散转入、集中转出
        if (self::detectScatterInConcentrateOut($transaction)) {
            $patterns[] = [
                'pattern' => self::PATTERN_SCATTER_IN_CONCENTRATE_OUT,
                'description' => '短期内资金分散转入、集中转出',
            ];
        }

        // 检测金额与经营规模不符
        if (self::detectAmountMismatch($transaction)) {
            $patterns[] = [
                'pattern' => self::PATTERN_AMOUNT_MISMATCH,
                'description' => '资金收付频率及金额与企业经营规模明显不符',
            ];
        }

        // 检测资金流向与经营范围不符
        if (self::detectFlowMismatch($transaction)) {
            $patterns[] = [
                'pattern' => self::PATTERN_FLOW_MISMATCH,
                'description' => '资金收付流向与企业经营范围明显不符',
            ];
        }

        // 检测长期闲置账户突然启用
        if (self::detectDormantSuddenActive($transaction)) {
            $patterns[] = [
                'pattern' => self::PATTERN_DORMANT_SUDDEN_ACTIVE,
                'description' => '长期闲置账户突然启用且发生大量资金收付',
            ];
        }

        $suspicious = ! empty($patterns);
        $riskLevel = self::determineRiskLevel($patterns);

        $result = [
            'suspicious' => $suspicious,
            'risk_level' => $riskLevel,
            'risk_label' => self::riskLabel($riskLevel),
            'patterns' => $patterns,
            'review_required' => $suspicious && $riskLevel !== 'low',
            'reported_at' => now()->toDateTimeString(),
            'law' => '《金融机构大额交易和可疑交易报告管理办法》',
        ];

        if ($suspicious) {
            self::audit('suspicious_transaction_detected', $transaction['user_id'] ?? 0, [
                'transaction_id' => $transaction['transaction_id'] ?? '',
                'amount' => $transaction['amount'] ?? 0,
                'risk_level' => $riskLevel,
                'patterns' => array_column($patterns, 'pattern'),
                'review_required' => $result['review_required'],
            ]);
        }

        return $result;
    }

    /**
     * 判断是否为可疑交易
     */
    public static function isSuspicious(array $transaction): bool
    {
        return self::analyze($transaction)['suspicious'];
    }

    /**
     * 分散转入、集中转出检测
     */
    private static function detectScatterInConcentrateOut(array $transaction): bool
    {
        $inCount = $transaction['recent_in_count'] ?? 0;
        $outCount = $transaction['recent_out_count'] ?? 0;

        return $inCount >= self::SCATTER_IN_COUNT && $outCount <= 2;
    }

    /**
     * 金额与经营规模不符检测
     */
    private static function detectAmountMismatch(array $transaction): bool
    {
        $amount = $transaction['amount'] ?? 0;
        $declaredAnnualRevenue = $transaction['declared_annual_revenue'] ?? 0;

        if ($declaredAnnualRevenue <= 0) {
            return false;
        }

        return $amount > ($declaredAnnualRevenue / 12 * 3); // 单笔超过季度收入
    }

    /**
     * 资金流向与经营范围不符检测
     */
    private static function detectFlowMismatch(array $transaction): bool
    {
        return $transaction['flow_mismatch'] ?? false;
    }

    /**
     * 长期闲置账户突然启用检测
     */
    private static function detectDormantSuddenActive(array $transaction): bool
    {
        $dormantDays = $transaction['dormant_days'] ?? 0;
        $amount = $transaction['amount'] ?? 0;

        return $dormantDays >= self::DORMANT_DAYS
            && $amount >= self::SUDDEN_ACTIVE_AMOUNT;
    }

    /**
     * 确定风险等级
     */
    private static function determineRiskLevel(array $patterns): string
    {
        $count = count($patterns);

        if ($count === 0) {
            return 'normal';
        }
        if ($count === 1) {
            return 'low';
        }
        if ($count === 2) {
            return 'medium';
        }

        return 'high';
    }

    /**
     * 风险等级标签
     */
    public static function riskLabel(string $level): string
    {
        return match ($level) {
            'normal' => '正常',
            'low' => '低风险',
            'medium' => '中风险',
            'high' => '高风险',
            default => '未知',
        };
    }

    /**
     * 记录可疑交易审计日志
     *
     * 依据《反洗钱法》和《金融机构大额交易和可疑交易报告管理办法》，
     * 可疑交易检测需记录审计日志，便于反洗钱合规审计。
     */
    private static function audit(string $event, int $userId, array $extra = []): void
    {
        if (! class_exists(\Kylin\AuditLog\Models\AuditLog::class)) {
            return;
        }

        try {
            \Kylin\AuditLog\Models\AuditLog::create([
                'event' => $event,
                'model_type' => 'transaction',
                'model_id' => $userId,
                'new_values' => $extra,
                'old_values' => null,
                'user_id' => auth()->id(),
                'ip' => request()?->ip(),
                'url' => request()?->fullUrl(),
                'tag' => 'risk-control-suspicious',
            ]);
        } catch (\Throwable $e) {
            Log::warning('可疑交易审计日志写入失败', [
                'error' => $e->getMessage(),
                'user_id' => $userId,
                'event' => $event,
            ]);
        }
    }
}