<?php

namespace App\Services;

use App\Interface\HistoryOwner;
use App\Models\Claim\Claim;
use App\Models\Task;
use Illuminate\Database\Eloquent\Model;

class TaskService
{
    public function addTask(
        HistoryService $history,
        Model $owner,
        $title,
        $due_at,
        $description = null,
        $target_user_id = null
    ) {
        $task = Task::create([
            'owner_type' => $owner->getMorphClass(),
            'owner_id' => $owner->getKey(),
            'user_id' => $target_user_id ?: auth()->id(),
            'title' => $title,
            'description' => $description,
            'due_at' => $due_at,
        ]);

        $label = $this->buildLabel($task);

        $this->record($history, $owner, "Added task {$label}", [
            'task_id' => $task->id,
            'title' => $task->title,
            'due_at' => optional($task->due_at)->toDateTimeString(),
            'assigned_to' => $task->user_id,
        ]);

        return $task;
    }

    public function completeTask(HistoryService $history, Task $task, Model $owner): void
    {
        $task->completed_at = now();
        $task->save();

        $this->record($history, $owner, "Completed task: {$task->title}", [
            'task_id' => $task->id,
            'title' => $task->title,
        ]);
    }

    public function deleteTask(HistoryService $history, Task $task, Model $owner): void
    {
        $context = [
            'task_id' => $task->id,
            'title' => $task->title,
            'due_at' => optional($task->due_at)->toDateTimeString(),
            'assigned_to' => $task->user_id,
        ];

        $task->delete();

        $this->record($history, $owner, "Deleted task: {$context['title']}", $context);
    }

    public function updateTask(HistoryService $history, Task $task, array $attributes): void
    {
        $before = $task->only(array_keys($attributes));

        $task->update($attributes);

        $changed = [];
        foreach ($task->getChanges() as $field => $newValue) {
            if (in_array($field, ['updated_at', 'created_at'])) {
                continue;
            }
            $changed[$field] = ['from' => $before[$field] ?? null, 'to' => $newValue];
        }

        if (empty($changed)) {
            return;
        }

        $this->record($history, $task->owner ?? auth()->user(), "Updated task: {$task->title}", [
            'task_id' => $task->id,
            'changed' => $changed,
        ]);
    }

    /**
     * Route the history entry to the correct owner: claim tasks dual-write to the
     * claim and its client, other history owners record directly, and anything
     * else (e.g. a personal task owned by a plain user) records against the actor.
     */
    private function record(HistoryService $history, Model $owner, string $event, array $context = []): void
    {
        if ($owner instanceof Claim) {
            $history->addForClaim($owner, $event, $context);
        } elseif ($owner instanceof HistoryOwner) {
            $history->add($owner, $event, $context);
        } else {
            $history->addForActor($event, $context);
        }
    }

    private function buildLabel(Task $task): string
    {
        $title = $task->title ? "titled '{$task->title}'" : null;
        $description = $task->description ? "described as '{$task->description}'" : null;
        $due = $task->due_at ? "due on " . $task->due_at->format('Y-m-d') : null;

        return implode(' and ', array_filter([$title, $description, $due]));
    }
}
