execute($filters, $limit, $offset); $total = $useCase->count($filters); $this->json([ 'success' => true, 'data' => array_map(fn ($t) => $t->toArray(), $tasks), 'meta' => [ 'total' => $total, 'limit' => $limit, 'offset' => $offset, ], ]); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } public function show(string $id): void { try { $useCase = new GetTasksUseCase(); $details = $useCase->getTaskWithDetails((int) $id); if ($details === null) { $this->json(['success' => false, 'error' => 'Task not found'], 404); return; } $this->json([ 'success' => true, 'data' => $details, ]); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } public function store(): void { try { $input = $this->getJsonInput(); $useCase = new CreateTaskUseCase(); $task = $useCase->execute($input); $this->json([ 'success' => true, 'data' => $task->toArray(), ], 201); } catch (\InvalidArgumentException $e) { $this->json(['success' => false, 'error' => $e->getMessage()], 400); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } public function update(string $id): void { try { $input = $this->getJsonInput(); $useCase = new GetTasksUseCase(); $task = $useCase->findById((int) $id); if ($task === null) { $this->json(['success' => false, 'error' => 'Task not found'], 404); return; } if (isset($input['title'])) { $task->setTitle($input['title']); } if (isset($input['description'])) { $task->setDescription($input['description']); } if (isset($input['type'])) { $task->setType($input['type']); } if (isset($input['due_date'])) { $task->setDueDate(new \DateTimeImmutable($input['due_date'])); } $repo = new \Infrastructure\Persistence\TaskRepository(); $repo->update($task); $this->json([ 'success' => true, 'data' => $task->toArray(), ]); } catch (\InvalidArgumentException $e) { $this->json(['success' => false, 'error' => $e->getMessage()], 400); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } public function destroy(string $id): void { try { $useCase = new DeleteTaskUseCase(); $useCase->execute((int) $id); $this->json([ 'success' => true, 'message' => 'Task deleted', ]); } catch (\InvalidArgumentException $e) { $this->json(['success' => false, 'error' => $e->getMessage()], 404); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } public function assign(string $id): void { try { $input = $this->getJsonInput(); $useCase = new AssignTaskUseCase(); $assignment = $useCase->execute((int) $id, $input); $this->json([ 'success' => true, 'data' => $assignment->toArray(), ], 201); } catch (\InvalidArgumentException $e) { $this->json(['success' => false, 'error' => $e->getMessage()], 400); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } public function updateStatus(string $id): void { $this->requireCsrf(); try { $input = $this->getJsonInput(); if (!isset($input['status']) || $input['status'] === '') { $this->json(['success' => false, 'error' => 'Status is required'], 400); return; } $updatedBy = $input['updated_by'] ?? 'api'; $updatedByType = $input['updated_by_type'] ?? 'human'; $useCase = new UpdateTaskStatusUseCase(); $task = $useCase->execute((int) $id, $input['status'], $updatedBy, $updatedByType); $this->json([ 'success' => true, 'data' => $task->toArray(), ]); } catch (\InvalidArgumentException $e) { $this->json(['success' => false, 'error' => $e->getMessage()], 400); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } public function storeResult(string $id): void { try { $input = $this->getJsonInput(); $useCase = new SaveTaskResultUseCase(); $result = $useCase->execute((int) $id, $input); $this->json([ 'success' => true, 'data' => $result->toArray(), ], 201); } catch (\InvalidArgumentException $e) { $this->json(['success' => false, 'error' => $e->getMessage()], 400); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } public function getResults(string $id): void { try { $repo = new \Infrastructure\Persistence\TaskResultRepository(); $results = $repo->findByTaskId((int) $id); $this->json([ 'success' => true, 'data' => array_map(fn ($r) => $r->toArray(), $results), ]); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } public function executeAI(string $id): void { try { $input = $this->getJsonInput(); $useCase = new ExecuteAITaskUseCase(); $result = $useCase->execute((int) $id, $input); $this->json([ 'success' => true, 'data' => $result->toArray(), ]); } catch (\InvalidArgumentException $e) { $this->json(['success' => false, 'error' => $e->getMessage()], 400); } catch (\RuntimeException $e) { $this->json(['success' => false, 'error' => $e->getMessage()], 503); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } public function statistics(): void { try { $taskUseCase = new GetTasksUseCase(); $taskStats = $taskUseCase->getStatistics(); $resultRepo = new \Infrastructure\Persistence\TaskResultRepository(); $tokenStats = $resultRepo->getTokenStatistics(); $modelUsage = $resultRepo->getModelUsage(); $this->json([ 'success' => true, 'data' => [ 'tasks' => $taskStats, 'tokens' => $tokenStats, 'models' => $modelUsage, ], ]); } catch (\Exception $e) { $this->jsonError($e->getMessage()); } } }