<?php

namespace Kylin\Guardian\Services;

use Illuminate\Support\Facades\Log;
use Kylin\Guardian\Enums\GuardianErrorCode;
use Kylin\Guardian\Exceptions\GuardianException;
use Kylin\Guardian\Models\GuardianBinding;

class GuardianNotifyService
{
    public function __construct(
        private readonly GuardianService $guardianService,
    ) {}

    /**
     * 通知监护人：未成年人登录
     *
     * @throws GuardianException
     */
    public function notifyLogin(int $bindingId): bool
    {
        $binding = $this->guardianService->findBinding($bindingId);

        if (! $binding->shouldNotifyOnLogin()) {
            return false;
        }

        $minorName = $binding->minorUser?->name ?? '未成年人';
        $title = '未成年人登录提醒';
        $body = "{$minorName}已登录游戏，请关注其游戏时长。";

        return $this->dispatch($binding, $title, $body, 'login');
    }

    /**
     * 通知监护人：未成年人消费
     *
     * @throws GuardianException
     */
    public function notifySpending(int $bindingId, float $amount): bool
    {
        $binding = $this->guardianService->findBinding($bindingId);

        if (! $binding->shouldNotifyOnSpending()) {
            return false;
        }

        $threshold = (float) config('kylin-guardian.spending_notify_threshold', 50);

        // 仅在达到阈值时通知
        if ($amount < $threshold) {
            return false;
        }

        $minorName = $binding->minorUser?->name ?? '未成年人';
        $title = '未成年人消费提醒';
        $body = "{$minorName}今日累计消费{$amount}元，已达到通知阈值{$threshold}元。";

        return $this->dispatch($binding, $title, $body, 'spending');
    }

    /**
     * 通知监护人：游戏时长预警
     *
     * @param  int  $remaining  剩余可玩分钟数
     *
     * @throws GuardianException
     */
    public function notifyTimeWarning(int $bindingId, int $remaining): bool
    {
        $binding = $this->guardianService->findBinding($bindingId);

        if (! $binding->shouldNotifyOnTimeWarning()) {
            return false;
        }

        $minorName = $binding->minorUser?->name ?? '未成年人';
        $title = '游戏时长预警';
        $body = $remaining > 0
            ? "{$minorName}今日剩余游戏时长{$remaining}分钟，即将达到限制。"
            : "{$minorName}今日游戏时长已达上限，游戏将被限制。";

        return $this->dispatch($binding, $title, $body, 'time_warning');
    }

    /**
     * 通知监护人：强制下线
     *
     * @throws GuardianException
     */
    public function notifyForceOffline(int $bindingId): bool
    {
        $binding = $this->guardianService->findBinding($bindingId);

        if (! $binding->shouldNotifyOnForceOffline()) {
            return false;
        }

        $minorName = $binding->minorUser?->name ?? '未成年人';
        $title = '强制下线通知';
        $body = "您已对{$minorName}执行强制下线操作，该账号已被限制登录。";

        return $this->dispatch($binding, $title, $body, 'force_offline');
    }

    /**
     * 通过配置的通知渠道分发通知
     */
    private function dispatch(GuardianBinding $binding, string $title, string $body, string $type): bool
    {
        $channels = $binding->getNotifyChannels();
        $guardian = $binding->guardian;

        if (! $guardian) {
            Log::warning('监护人通知发送失败：监护人不存在', [
                'binding_id' => $binding->id,
                'type' => $type,
            ]);

            return false;
        }

        $payload = [
            'guardian_id' => $guardian->id,
            'user_id' => $guardian->user_id,
            'binding_id' => $binding->id,
            'minor_user_id' => $binding->minor_user_id,
            'type' => $type,
            'title' => $title,
            'body' => $body,
            'channels' => $channels,
            'phone' => $guardian->phone,
        ];

        $successCount = 0;
        foreach ($channels as $channel) {
            try {
                $this->sendViaChannel($channel, $payload);
                $successCount++;
            } catch (\Throwable $e) {
                Log::error('监护人通知发送异常', [
                    'channel' => $channel,
                    'binding_id' => $binding->id,
                    'type' => $type,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        $this->audit('guardian_notified', $binding, [
            'type' => $type,
            'channels' => $channels,
            'success_count' => $successCount,
        ]);

        return true;
    }

    /**
     * 记录监护人通知审计日志
     *
     * 依据《未成年人保护法》和《个人信息保护法》，
     * 监护人通知发送需记录审计日志，便于追溯通知送达情况。
     */
    private function audit(string $event, GuardianBinding $binding, array $extra = []): void
    {
        if (! class_exists(\Kylin\AuditLog\Models\AuditLog::class)) {
            return;
        }

        try {
            \Kylin\AuditLog\Models\AuditLog::create([
                'event' => $event,
                'model_type' => GuardianBinding::class,
                'model_id' => $binding->id,
                'new_values' => $extra,
                'old_values' => null,
                'user_id' => auth()->id(),
                'ip' => request()?->ip(),
                'url' => request()?->fullUrl(),
                'tag' => 'guardian-notify',
            ]);
        } catch (\Throwable $e) {
            Log::warning('监护人通知审计日志写入失败', [
                'error' => $e->getMessage(),
                'binding_id' => $binding->id,
                'event' => $event,
            ]);
        }
    }

    /**
     * 通过指定渠道发送通知
     */
    private function sendViaChannel(string $channel, array $payload): void
    {
        match ($channel) {
            'push' => $this->sendPush($payload),
            'sms' => $this->sendSms($payload),
            'email' => $this->sendEmail($payload),
            default => Log::warning("不支持的通知渠道: {$channel}"),
        };
    }

    /**
     * 推送通知（JPush/极推/友盟等）
     */
    private function sendPush(array $payload): void
    {
        // 通过 kylin/notification 包的推送渠道发送
        // 实际调用 JPushChannel / GeTuiChannel / UMengChannel 等
        Log::info('监护人推送通知', [
            'user_id' => $payload['user_id'],
            'title' => $payload['title'],
            'body' => $payload['body'],
        ]);

        // 示例：使用 Laravel Notification 系统
        // $user = User::find($payload['user_id']);
        // $user->notify(new GuardianNotification($payload));
    }

    /**
     * 短信通知
     */
    private function sendSms(array $payload): void
    {
        // 通过 kylin/notification 包的短信渠道发送
        Log::info('监护人短信通知', [
            'phone' => $payload['phone'],
            'body' => $payload['body'],
        ]);
    }

    /**
     * 邮件通知
     */
    private function sendEmail(array $payload): void
    {
        // 通过 kylin/notification 包的邮件渠道发送
        Log::info('监护人邮件通知', [
            'user_id' => $payload['user_id'],
            'title' => $payload['title'],
            'body' => $payload['body'],
        ]);
    }
}
