<?php

namespace App\Services\System;

use App\Models\System\Notification;
use App\Services\WebSocket\WebSocketService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class NotificationService
{
    /**
     * @var WebSocketService
     */
    protected $webSocketService;

    /**
     * NotificationService constructor
     */
    public function __construct()
    {
        $this->webSocketService = app(WebSocketService::class);
    }

    /**
     * 获取通知列表
     *
     * @param array $params
     * @return array
     */
    public function getList(array $params): array
    {
        $query = Notification::query();

        // 过滤用户ID
        if (!empty($params['user_id'])) {
            $query->where('user_id', $params['user_id']);
        }

        // 关键字搜索
        if (!empty($params['keyword'])) {
            $query->where(function ($q) use ($params) {
                $q->where('title', 'like', '%' . $params['keyword'] . '%')
                    ->orWhere('content', 'like', '%' . $params['keyword'] . '%');
            });
        }

        // 过滤阅读状态
        if (isset($params['is_read']) && $params['is_read'] !== '') {
            $query->where('is_read', $params['is_read']);
        }

        // 过滤通知类型
        if (!empty($params['type'])) {
            $query->where('type', $params['type']);
        }

        // 过滤通知分类
        if (!empty($params['category'])) {
            $query->where('category', $params['category']);
        }

        // 日期范围
        if (!empty($params['start_date'])) {
            $query->where('created_at', '>=', $params['start_date']);
        }
        if (!empty($params['end_date'])) {
            $query->where('created_at', '<=', $params['end_date']);
        }

        $query->orderBy('created_at', 'desc');

        $pageSize = $params['page_size'] ?? 20;
        $list = $query->paginate($pageSize);

        return [
            'list' => $list->items(),
            'total' => $list->total(),
            'page' => $list->currentPage(),
            'page_size' => $list->perPage(),
        ];
    }

    /**
     * 获取未读通知列表
     *
     * @param int $userId
     * @param int $limit
     * @param int $page
     * @param string|null $type
     * @return array
     */
    public function getUnreadNotifications(int $userId, int $limit = 10, int $page = 1, ?string $type = null): array
    {
        $query = Notification::where('user_id', $userId)
            ->where('is_read', false);

        // 按类型过滤
        if (!empty($type)) {
            $query->where('type', $type);
        }

        $query->orderBy('created_at', 'desc');

        // 分页处理
        $list = $query->paginate($limit, ['*'], 'page', $page);

        return [
            'list' => $list->items(),
            'total' => $list->total(),
            'page' => $list->currentPage(),
            'page_size' => $list->perPage(),
        ];
    }

    /**
     * 获取未读通知数量
     *
     * @param int $userId
     * @return int
     */
    public function getUnreadCount(int $userId): int
    {
        return Notification::where('user_id', $userId)
            ->where('is_read', false)
            ->count();
    }

    /**
     * 根据ID获取通知
     *
     * @param int $id
     * @return Notification|null
     */
    public function getById(int $id): ?Notification
    {
        return Notification::find($id);
    }

    /**
     * 创建通知
     *
     * @param array $data
     * @return Notification
     */
    public function create(array $data): Notification
    {
        $notification = Notification::create($data);

        // 如果用户在线，立即通过WebSocket发送
        if ($this->webSocketService->isUserOnline($data['user_id'])) {
            $this->sendViaWebSocket($notification);
        }

        return $notification;
    }

    /**
     * 批量创建通知
     *
     * @param array $notificationsData
     * @return array
     */
    public function batchCreate(array $notificationsData): array
    {
        $notifications = [];

        DB::beginTransaction();
        try {
            foreach ($notificationsData as $data) {
                $notification = Notification::create($data);
                $notifications[] = $notification;

                // 如果用户在线，立即通过WebSocket发送
                if ($this->webSocketService->isUserOnline($data['user_id'])) {
                    $this->sendViaWebSocket($notification);
                }
            }
            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('批量创建通知失败', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            throw $e;
        }

        return $notifications;
    }

    /**
     * 发送系统通知给单个用户
     *
     * @param int $userId
     * @param string $title
     * @param string $content
     * @param string $type
     * @param string $category
     * @param array $extraData
     * @return Notification
     */
    public function sendToUser(
        int $userId,
        string $title,
        string $content,
        string $type = Notification::TYPE_INFO,
        string $category = Notification::CATEGORY_SYSTEM,
        array $extraData = []
    ): Notification {
        $data = [
            'user_id' => $userId,
            'title' => $title,
            'content' => $content,
            'type' => $type,
            'category' => $category,
            'data' => $extraData,
            'is_read' => false,
        ];

        return $this->create($data);
    }

    /**
     * 发送系统通知给多个用户
     *
     * @param array $userIds
     * @param string $title
     * @param string $content
     * @param string $type
     * @param string $category
     * @param array $extraData
     * @return array
     */
    public function sendToUsers(
        array $userIds,
        string $title,
        string $content,
        string $type = Notification::TYPE_INFO,
        string $category = Notification::CATEGORY_SYSTEM,
        array $extraData = []
    ): array {
        $notificationsData = [];

        foreach ($userIds as $userId) {
            $notificationsData[] = [
                'user_id' => $userId,
                'title' => $title,
                'content' => $content,
                'type' => $type,
                'category' => $category,
                'data' => $extraData,
                'is_read' => false,
                'created_at' => now(),
                'updated_at' => now(),
            ];
        }

        return $this->batchCreate($notificationsData);
    }

    /**
     * 发送系统广播通知（所有用户）
     *
     * @param string $title
     * @param string $content
     * @param string $type
     * @param string $category
     * @param array $extraData
     * @return array
     */
    public function broadcast(
        string $title,
        string $content,
        string $type = Notification::TYPE_INFO,
        string $category = Notification::CATEGORY_ANNOUNCEMENT,
        array $extraData = []
    ): array {
        // 获取所有用户ID
        $userIds = \App\Models\Auth\User::where('status', 1)->pluck('id')->toArray();

        return $this->sendToUsers($userIds, $title, $content, $type, $category, $extraData);
    }

    /**
     * 通过WebSocket发送通知
     *
     * @param Notification $notification
     * @return bool
     */
    protected function sendViaWebSocket(Notification $notification): bool
    {
        $data = [
            'type' => 'notification',
            'data' => [
                'id' => $notification->id,
                'title' => $notification->title,
                'content' => $notification->content,
                'type' => $notification->type,
                'category' => $notification->category,
                'data' => $notification->data,
                'action_type' => $notification->action_type,
                'action_data' => $notification->action_data,
                'timestamp' => $notification->created_at->timestamp,
            ]
        ];

        $result = $this->webSocketService->sendToUser($notification->user_id, $data);

        if ($result) {
            $notification->markAsSent();
        } else {
            $notification->incrementRetry();
        }

        return $result;
    }

    /**
     * 重试发送未发送的通知
     *
     * @param int $limit
     * @return int
     */
    public function retryUnsentNotifications(int $limit = 100): int
    {
        $notifications = Notification::where('sent_via_websocket', false)
            ->where('retry_count', '<', 3)
            ->where('created_at', '>', now()->subHours(24))
            ->orderBy('created_at', 'desc')
            ->limit($limit)
            ->get();

        $sentCount = 0;

        foreach ($notifications as $notification) {
            if ($this->webSocketService->isUserOnline($notification->user_id)) {
                if ($this->sendViaWebSocket($notification)) {
                    $sentCount++;
                }
            }
        }

        return $sentCount;
    }

    /**
     * 标记通知为已读
     *
     * @param int $id
     * @param int $userId
     * @return bool
     */
    public function markAsRead(int $id, int $userId): bool
    {
        $notification = Notification::where('id', $id)
            ->where('user_id', $userId)
            ->first();

        if (!$notification) {
            return false;
        }

        return $notification->markAsRead();
    }

    /**
     * 批量标记通知为已读
     *
     * @param array $ids
     * @param int $userId
     * @return int
     */
    public function batchMarkAsRead(array $ids, int $userId): int
    {
        return Notification::where('user_id', $userId)
            ->whereIn('id', $ids)
            ->update([
                'is_read' => true,
                'read_at' => now(),
            ]);
    }

    /**
     * 标记所有通知为已读
     *
     * @param int $userId
     * @return int
     */
    public function markAllAsRead(int $userId): int
    {
        return Notification::where('user_id', $userId)
            ->where('is_read', false)
            ->update([
                'is_read' => true,
                'read_at' => now(),
            ]);
    }

    /**
     * 删除通知
     *
     * @param int $id
     * @param int $userId
     * @return bool
     */
    public function delete(int $id, int $userId): bool
    {
        $notification = Notification::where('id', $id)
            ->where('user_id', $userId)
            ->first();

        if (!$notification) {
            return false;
        }

        return $notification->delete();
    }

    /**
     * 批量删除通知
     *
     * @param array $ids
     * @param int $userId
     * @return int
     */
    public function batchDelete(array $ids, int $userId): int
    {
        return Notification::where('user_id', $userId)
            ->whereIn('id', $ids)
            ->delete();
    }

    /**
     * 清空已读通知
     *
     * @param int $userId
     * @return int
     */
    public function clearReadNotifications(int $userId): int
    {
        return Notification::where('user_id', $userId)
            ->where('is_read', true)
            ->delete();
    }

    /**
     * 获取通知统计
     *
     * @param int $userId
     * @return array
     */
    public function getStatistics(int $userId): array
    {
        $total = Notification::where('user_id', $userId)->count();
        $unread = Notification::where('user_id', $userId)->where('is_read', false)->count();
        $read = Notification::where('user_id', $userId)->where('is_read', true)->count();

        // 按类型统计
        $byType = Notification::where('user_id', $userId)
            ->selectRaw('type, COUNT(*) as count')
            ->groupBy('type')
            ->pluck('count', 'type')
            ->toArray();

        // 按分类统计
        $byCategory = Notification::where('user_id', $userId)
            ->selectRaw('category, COUNT(*) as count')
            ->groupBy('category')
            ->pluck('count', 'category')
            ->toArray();

        return [
            'total' => $total,
            'unread' => $unread,
            'read' => $read,
            'by_type' => $byType,
            'by_category' => $byCategory,
        ];
    }

    /**
     * 发送任务通知
     *
     * @param int $userId
     * @param string $title
     * @param string $content
     * @param array $taskData
     * @return Notification
     */
    public function sendTaskNotification(int $userId, string $title, string $content, array $taskData = []): Notification
    {
        return $this->sendToUser(
            $userId,
            $title,
            $content,
            Notification::TYPE_TASK,
            Notification::CATEGORY_TASK,
            array_merge(['task' => $taskData], $taskData)
        );
    }

    /**
     * 发送系统维护通知
     *
     * @param string $title
     * @param string $content
     * @param array $maintenanceData
     * @return array
     */
    public function sendMaintenanceNotification(string $title, string $content, array $maintenanceData = []): array
    {
        return $this->broadcast(
            $title,
            $content,
            Notification::TYPE_WARNING,
            Notification::CATEGORY_ANNOUNCEMENT,
            array_merge(['maintenance' => $maintenanceData], $maintenanceData)
        );
    }

    /**
     * 发送新消息通知
     *
     * @param int $userId
     * @param string $title
     * @param string $content
     * @param array $messageData
     * @return Notification
     */
    public function sendNewMessageNotification(int $userId, string $title, string $content, array $messageData = []): Notification
    {
        return $this->sendToUser(
            $userId,
            $title,
            $content,
            Notification::TYPE_INFO,
            Notification::CATEGORY_MESSAGE,
            array_merge(['message' => $messageData], $messageData)
        );
    }

    /**
     * 发送提醒通知
     *
     * @param int $userId
     * @param string $title
     * @param string $content
     * @param array $reminderData
     * @return Notification
     */
    public function sendReminderNotification(int $userId, string $title, string $content, array $reminderData = []): Notification
    {
        return $this->sendToUser(
            $userId,
            $title,
            $content,
            Notification::TYPE_WARNING,
            Notification::CATEGORY_REMINDER,
            array_merge(['reminder' => $reminderData], $reminderData)
        );
    }
}
