<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreScheduledTaskRequest;
use App\Http\Requests\UpdateScheduledTaskRequest;
use App\Http\Resources\ScheduledTaskResource;
use App\Http\Resources\ScheduledTaskRunResource;
use App\ScheduledTasks\ScheduledTaskRepository;
use App\ScheduledTasks\SlotLoadService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Carbon;
use Mtc\MercuryDataModels\ScheduledTask;
use Mtc\MercuryDataModels\ScheduledTaskRun;

class ScheduledTaskController extends Controller
{
    public function __construct(private readonly ScheduledTaskRepository $repository)
    {
        $this->middleware(['permission:manage-scheduled-tasks']);
    }

    public function index(): JsonResponse
    {
        $tasks = ScheduledTask::query()
            ->with('parent:id,name')
            ->orderBy('name')
            ->paginate(50)
            ->through(fn (ScheduledTask $task) => [
                'id' => $task->id,
                'name' => $task->name,
                'managed_by' => $task->managed_by,
                'enabled' => $task->enabled,
                'trigger_type' => $task->trigger_type,
                'trigger_summary' => $this->triggerSummary($task),
                'next_due_at' => $task->next_due_at?->format('Y-m-d H:i'),
                'last_run_at' => $task->last_run_at?->format('Y-m-d H:i'),
                'last_outcome' => $task->runs()->finished()->latest('finished_at')->first()?->status,
            ]);

        return response()->json($tasks);
    }

    public function store(StoreScheduledTaskRequest $request): JsonResponse
    {
        $task = $this->repository->create($request->only('name'));

        return response()->json(['id' => $task->id], Response::HTTP_CREATED);
    }

    public function show(ScheduledTask $scheduledTask): ScheduledTaskResource
    {
        $scheduledTask->load('actions', 'children');

        return new ScheduledTaskResource($scheduledTask);
    }

    public function update(
        UpdateScheduledTaskRequest $request,
        ScheduledTask $scheduledTask
    ): ScheduledTaskResource {
        $task = $this->repository->update(
            $scheduledTask,
            $request->safe()->except('actions'),
            $request->validated('actions', [])
        );

        return new ScheduledTaskResource($task);
    }

    public function destroy(ScheduledTask $scheduledTask): Response|JsonResponse
    {
        if ($scheduledTask->isSystemManaged()) {
            return response()->json(['message' => 'System tasks cannot be deleted'], 422);
        }

        $this->repository->delete($scheduledTask);

        return response()->noContent();
    }

    public function run(ScheduledTask $scheduledTask): ScheduledTaskRunResource|JsonResponse
    {
        if ($scheduledTask->isSystemManaged()) {
            return response()->json(['message' => 'System tasks cannot be run manually'], 422);
        }

        return new ScheduledTaskRunResource($this->repository->runNow($scheduledTask));
    }

    public function runs(ScheduledTask $scheduledTask): JsonResponse
    {
        $runs = $scheduledTask->runs()
            ->orderByDesc('scheduled_for')
            ->paginate(25)
            ->through(fn (ScheduledTaskRun $run) => (new ScheduledTaskRunResource($run))->resolve());

        return response()->json($runs);
    }

    public function retry(ScheduledTaskRun $scheduledTaskRun): ScheduledTaskRunResource|JsonResponse
    {
        if ($scheduledTaskRun->status !== ScheduledTaskRun::STATUS_FAILED) {
            return response()->json(['message' => 'Only failed runs can be retried'], 422);
        }

        return new ScheduledTaskRunResource($this->repository->retry($scheduledTaskRun));
    }

    public function today(): JsonResponse
    {
        $runs = ScheduledTaskRun::query()
            ->with('task:id,name')
            ->whereBetween('scheduled_for', [Carbon::today(), Carbon::today()->endOfDay()])
            ->orderBy('scheduled_for')
            ->get()
            ->map(fn (ScheduledTaskRun $run) => (new ScheduledTaskRunResource($run))->resolve());

        return response()->json(['data' => $runs]);
    }

    public function slotLoad(Request $request, SlotLoadService $slotLoad): JsonResponse
    {
        $request->validate([
            'times' => ['required', 'array', 'min:1'],
            'times.*' => ['date_format:H:i'],
        ]);

        return response()->json(['data' => $slotLoad->check($request->input('times'))]);
    }

    private function triggerSummary(ScheduledTask $task): string
    {
        return match ($task->trigger_type) {
            ScheduledTask::TRIGGER_AFTER_TASK => sprintf(
                'After: %s (%s)',
                $task->parent?->name ?? 'unknown task',
                str_replace('_', ' ', $task->parent_condition)
            ),
            ScheduledTask::TRIGGER_AFTER_EVENT => 'After event: ' . $task->event
                . ($task->event_filter ? " ({$task->event_filter})" : ''),
            default => collect($task->schedule_rules ?? [])
                ->map(fn (array $rule) => ucfirst($rule['frequency'] ?? '') . ' ' . ($rule['time'] ?? ''))
                ->implode(', ') ?: 'Not scheduled',
        };
    }
}
