<?php

namespace App\Support;

use Illuminate\Support\Facades\DB;

final class AgentOverdueGuard
{
    public static function agentHasOverdueBills(int $agentNodeId): bool
    {
        if ($agentNodeId <= 0) {
            return false;
        }

        return DB::table('settlement_bills')
            ->where('owner_type', 'agent')
            ->where('owner_id', $agentNodeId)
            ->where('status', 'overdue')
            ->where('unpaid_amount', '>', 0)
            ->exists();
    }

    public static function agentHasSevereOverdueBills(int $agentNodeId, int $days = 7): bool
    {
        if ($agentNodeId <= 0) {
            return false;
        }

        $cutoff = now()->subDays($days);

        return DB::table('settlement_bills')
            ->where('owner_type', 'agent')
            ->where('owner_id', $agentNodeId)
            ->where('status', 'overdue')
            ->where('unpaid_amount', '>', 0)
            ->where('updated_at', '<', $cutoff)
            ->exists();
    }

    public static function agentLineHasSevereOverdueBills(int $agentNodeId, int $days = 7): bool
    {
        if ($agentNodeId <= 0) {
            return false;
        }

        $agent = DB::table('agent_nodes')->where('id', $agentNodeId)->first();
        if ($agent === null) {
            return false;
        }

        // 获取该代理的所有祖先节点ID（包括自己）
        $path = (string) $agent->path;
        if ($path === '') {
            // 根节点，只检查自己
            $ancestorIds = [$agentNodeId];
        } else {
            // 解析 path 获取所有祖先ID
            $parts = explode('/', trim($path, '/'));
            $ancestorIds = array_map('intval', $parts);
            $ancestorIds[] = $agentNodeId;
        }

        $cutoff = now()->subDays($days);

        return DB::table('settlement_bills')
            ->where('owner_type', 'agent')
            ->where('status', 'overdue')
            ->where('unpaid_amount', '>', 0)
            ->where('updated_at', '<', $cutoff)
            ->whereIn('owner_id', $ancestorIds)
            ->exists();
    }

    public static function assertAgentMayGrantCredit(int $agentNodeId): void
    {
        if (self::agentHasOverdueBills($agentNodeId)) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'credit' => ['agent_overdue'],
            ]);
        }
    }

    public static function assertAgentLineMayPlaceBet(int $agentNodeId, ?int $severeOverdueDays = null): void
    {
        $days = $severeOverdueDays ?? config('agent_line_defaults.overdue.severe_days_threshold', 7);
        if (self::agentLineHasSevereOverdueBills($agentNodeId, $days)) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'credit' => ['agent_line_severe_overdue'],
            ]);
        }
    }

    public static function parentHasOverdueBills(int $agentNodeId): bool
    {
        if ($agentNodeId <= 0) {
            return false;
        }

        $agent = DB::table('agent_nodes')->where('id', $agentNodeId)->first();
        if ($agent === null || $agent->parent_id === null) {
            return false;
        }

        return DB::table('settlement_bills')
            ->where('owner_type', 'agent')
            ->where('owner_id', $agent->parent_id)
            ->where('status', 'overdue')
            ->where('unpaid_amount', '>', 0)
            ->exists();
    }

    public static function assertMayOperateWhenParentOverdue(int $agentNodeId): void
    {
        if (! config('agent_line_defaults.overdue.cascade_freeze_on_parent_overdue', false)) {
            return;
        }

        if (self::parentHasOverdueBills($agentNodeId)) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'parent_id' => ['parent_overdue'],
            ]);
        }
    }
}
