<?php

namespace App\Services\System;

use App\Models\System\Task;
use App\Services\System\NotificationService;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Log;

class TaskService
{
    /**
     * @var NotificationService
     */
    protected $notificationService;

    /**
     * TaskService constructor
     */
    public function __construct(NotificationService $notificationService)
    {
        $this->notificationService = $notificationService;
    }

    public function getList(array $params): array
    {
        $query = Task::query();

        if (!empty($params['keyword'])) {
            $query->where(function ($q) use ($params) {
                $q->where('name', 'like', '%' . $params['keyword'] . '%')
                    ->orWhere('command', 'like', '%' . $params['keyword'] . '%');
            });
        }

        if (isset($params['is_active']) && $params['is_active'] !== '') {
            $query->where('is_active', $params['is_active']);
        }

        if (!empty($params['type'])) {
            $query->where('type', $params['type']);
        }

        $query->orderBy('id');

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

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

    public function getAll(): array
    {
        return Task::all()->toArray();
    }

    public function getById(int $id): ?Task
    {
        return Task::find($id);
    }

    public function create(array $data): Task
    {
        Validator::make($data, [
            'name' => 'required|string|max:100',
            'command' => 'required|string|max:255',
            'type' => 'required|string|in:command,job,closure',
            'expression' => 'required|string',
        ])->validate();

        return Task::create($data);
    }

    public function update(int $id, array $data): Task
    {
        $task = Task::findOrFail($id);

        Validator::make($data, [
            'name' => 'sometimes|required|string|max:100',
            'command' => 'sometimes|required|string|max:255',
            'type' => 'sometimes|required|string|in:command,job,closure',
            'expression' => 'sometimes|required|string',
        ])->validate();

        $task->update($data);
        return $task;
    }

    public function delete(int $id): bool
    {
        $task = Task::findOrFail($id);
        return $task->delete();
    }

    public function batchDelete(array $ids): bool
    {
        Task::whereIn('id', $ids)->delete();
        return true;
    }

    public function batchUpdateStatus(array $ids, bool $status): bool
    {
        Task::whereIn('id', $ids)->update(['is_active' => $status]);
        return true;
    }

    public function run(int $id): array
    {
        $task = Task::findOrFail($id);

        $startTime = microtime(true);
        $output = '';
        $status = 'success';
        $errorMessage = '';

        try {
            switch ($task->type) {
                case 'command':
                    $command = $task->command;
                    if ($task->run_in_background) {
                        $command .= ' > /dev/null 2>&1 &';
                    }
                    exec($command, $output, $statusCode);
                    $output = implode("\n", $output);
                    if ($statusCode !== 0) {
                        throw new \Exception('Command failed with status code: ' . $statusCode);
                    }
                    break;

                case 'job':
                    $jobClass = $task->command;
                    if (class_exists($jobClass)) {
                        dispatch(new $jobClass());
                    } else {
                        throw new \Exception('Job class not found: ' . $jobClass);
                    }
                    break;

                case 'closure':
                    throw new \Exception('Closure type tasks cannot be run directly');
            }

            $task->increment('run_count');
        } catch (\Exception $e) {
            $status = 'error';
            $errorMessage = $e->getMessage();
            $task->increment('failed_count');
        }

        $executionTime = round((microtime(true) - $startTime) * 1000);

        $task->update([
            'last_run_at' => now(),
            'last_output' => substr($output, 0, 10000),
        ]);

        // 发送任务执行结果通知
        $this->sendTaskNotification($task, $status, $errorMessage, $executionTime);

        return [
            'status' => $status,
            'output' => $output,
            'error_message' => $errorMessage,
            'execution_time' => $executionTime,
        ];
    }

    public function getStatistics(): array
    {
        $total = Task::count();
        $active = Task::where('is_active', true)->count();
        $inactive = Task::where('is_active', false)->count();

        return [
            'total' => $total,
            'active' => $active,
            'inactive' => $inactive,
        ];
    }

    /**
     * 发送任务执行结果通知
     *
     * @param Task $task
     * @param string $status
     * @param string|null $errorMessage
     * @param int $executionTime
     * @return void
     */
    protected function sendTaskNotification(Task $task, string $status, ?string $errorMessage, int $executionTime): void
    {
        try {
            // 只对失败的任务或重要的成功任务发送通知
            // 这里可以根据实际需求调整通知策略

            if ($status === 'error') {
                // 任务失败通知
                $title = '任务执行失败: ' . $task->name;
                $content = sprintf(
                    "任务 %s 执行失败，错误信息：%s\n执行时间：%d 毫秒",
                    $task->name,
                    $errorMessage ?: '未知错误',
                    $executionTime
                );

                // 获取管理员用户ID列表
                $adminUserIds = $this->getAdminUserIds();

                if (!empty($adminUserIds)) {
                    $this->notificationService->sendToUsers(
                        $adminUserIds,
                        $title,
                        $content,
                        \App\Models\System\Notification::TYPE_ERROR,
                        \App\Models\System\Notification::CATEGORY_TASK,
                        [
                            'task_id' => $task->id,
                            'task_name' => $task->name,
                            'command' => $task->command,
                            'error_message' => $errorMessage,
                            'execution_time' => $executionTime,
                            'last_run_at' => $task->last_run_at?->toDateTimeString()
                        ]
                    );
                }
            } elseif ($executionTime > 60000) {
                // 执行时间超过1分钟的成功任务，发送通知
                $title = '任务执行完成: ' . $task->name;
                $content = sprintf(
                    "任务 %s 执行成功，耗时：%.2f 秒",
                    $task->name,
                    $executionTime / 1000
                );

                $adminUserIds = $this->getAdminUserIds();

                if (!empty($adminUserIds)) {
                    $this->notificationService->sendToUsers(
                        $adminUserIds,
                        $title,
                        $content,
                        \App\Models\System\Notification::TYPE_SUCCESS,
                        \App\Models\System\Notification::CATEGORY_TASK,
                        [
                            'task_id' => $task->id,
                            'task_name' => $task->name,
                            'execution_time' => $executionTime,
                            'last_run_at' => $task->last_run_at?->toDateTimeString()
                        ]
                    );
                }
            }
        } catch (\Exception $e) {
            Log::error('发送任务通知失败', [
                'task_id' => $task->id,
                'error' => $e->getMessage()
            ]);
        }
    }

    /**
     * 获取管理员用户ID列表
     *
     * @return array
     */
    protected function getAdminUserIds(): array
    {
        try {
            // 获取拥有管理员权限的用户
            // 这里可以根据实际业务逻辑调整，例如获取特定角色的用户
            $adminUserIds = \App\Models\Auth\User::where('status', 1)
                ->whereHas('roles', function ($query) {
                    $query->where('name', 'admin');
                })
                ->pluck('id')
                ->toArray();

            return $adminUserIds;
        } catch (\Exception $e) {
            Log::error('获取管理员用户列表失败', [
                'error' => $e->getMessage()
            ]);
            return [];
        }
    }
}
