<?php

namespace Modules\Operations\Services;

use App\Models\ActivityLogModel;
use App\Models\EmployeeModel;
use App\Models\OperationsTaskChecklistItemModel;
use App\Models\OperationsTaskModel;

class OperationsTaskService
{
    protected OperationsTaskModel $tasks;
    protected OperationsTaskChecklistItemModel $checklist;
    protected EmployeeModel $employees;
    protected ActivityLogModel $activity;

    public function __construct()
    {
        $this->tasks     = new OperationsTaskModel();
        $this->checklist = new OperationsTaskChecklistItemModel();
        $this->employees = new EmployeeModel();
        $this->activity  = new ActivityLogModel();
    }

    public function create(array $input, ?int $actingUserId): array
    {
        $title = trim((string) ($input['title'] ?? ''));
        if ($title === '') {
            return ['success' => false, 'errors' => ['title' => 'Title is required.']];
        }

        $priority = (string) ($input['priority'] ?? 'normal');
        if (! in_array($priority, OperationsTaskModel::PRIORITIES, true)) {
            $priority = 'normal';
        }

        $status = (string) ($input['status'] ?? 'open');
        if (! in_array($status, ['open', 'in_progress'], true)) {
            $status = 'open';
        }

        $assigneeId = (int) ($input['assignee_employee_id'] ?? 0);
        if ($assigneeId > 0) {
            $employee = $this->employees->find($assigneeId);
            if (! $employee || ($employee['status'] ?? '') !== 'active') {
                return ['success' => false, 'errors' => ['assignee_employee_id' => 'Select an active employee.']];
            }
        } else {
            $assigneeId = null;
        }

        $data = [
            'number'               => $this->tasks->nextNumber(),
            'title'                => $title,
            'description'          => trim((string) ($input['description'] ?? '')) ?: null,
            'priority'             => $priority,
            'status'               => $status,
            'due_date'             => $this->nullableDate($input['due_date'] ?? null),
            'assignee_employee_id' => $assigneeId,
            'created_by'           => $actingUserId,
            'updated_by'           => $actingUserId,
        ];

        if (! $this->tasks->insert($data, true)) {
            return ['success' => false, 'errors' => $this->tasks->errors()];
        }

        $id = (int) $this->tasks->getInsertID();
        $this->activity->log('operations_tasks', 'created', $actingUserId, "Created task #{$id} ({$data['number']})", (string) $id);

        return ['success' => true, 'id' => $id];
    }

    public function update(int $id, array $input, ?int $actingUserId): array
    {
        $task = $this->tasks->find($id);
        if (! $task) {
            return ['success' => false, 'errors' => ['id' => 'Task not found.']];
        }

        if (! in_array($task['status'], OperationsTaskModel::OPEN_STATUSES, true)) {
            return ['success' => false, 'errors' => ['status' => 'Only open tasks can be edited.']];
        }

        $title = trim((string) ($input['title'] ?? ''));
        if ($title === '') {
            return ['success' => false, 'errors' => ['title' => 'Title is required.']];
        }

        $priority = (string) ($input['priority'] ?? $task['priority']);
        if (! in_array($priority, OperationsTaskModel::PRIORITIES, true)) {
            $priority = $task['priority'];
        }

        $status = (string) ($input['status'] ?? $task['status']);
        if (! in_array($status, OperationsTaskModel::OPEN_STATUSES, true)) {
            $status = $task['status'];
        }

        $assigneeId = (int) ($input['assignee_employee_id'] ?? 0);
        if ($assigneeId > 0) {
            $employee = $this->employees->find($assigneeId);
            if (! $employee || ($employee['status'] ?? '') !== 'active') {
                return ['success' => false, 'errors' => ['assignee_employee_id' => 'Select an active employee.']];
            }
        } else {
            $assigneeId = null;
        }

        $data = [
            'title'                => $title,
            'description'          => trim((string) ($input['description'] ?? '')) ?: null,
            'priority'             => $priority,
            'status'               => $status,
            'due_date'             => $this->nullableDate($input['due_date'] ?? null),
            'assignee_employee_id' => $assigneeId,
            'updated_by'           => $actingUserId,
        ];

        if (! $this->tasks->update($id, $data)) {
            return ['success' => false, 'errors' => $this->tasks->errors()];
        }

        $this->activity->log('operations_tasks', 'updated', $actingUserId, "Updated task #{$id}", (string) $id);

        return ['success' => true];
    }

    public function complete(int $id, ?int $actingUserId): array
    {
        $task = $this->tasks->find($id);
        if (! $task) {
            return ['success' => false, 'error' => 'Task not found.'];
        }

        if (! in_array($task['status'], OperationsTaskModel::OPEN_STATUSES, true)) {
            return ['success' => false, 'error' => 'Only open tasks can be completed.'];
        }

        $this->tasks->update($id, [
            'status'       => 'completed',
            'completed_at' => date('Y-m-d H:i:s'),
            'updated_by'   => $actingUserId,
        ]);
        $this->activity->log('operations_tasks', 'completed', $actingUserId, "Completed task #{$id}", (string) $id);

        return ['success' => true];
    }

    public function cancel(int $id, ?int $actingUserId): array
    {
        $task = $this->tasks->find($id);
        if (! $task) {
            return ['success' => false, 'error' => 'Task not found.'];
        }

        if (! in_array($task['status'], OperationsTaskModel::OPEN_STATUSES, true)) {
            return ['success' => false, 'error' => 'Only open tasks can be cancelled.'];
        }

        $this->tasks->update($id, [
            'status'     => 'cancelled',
            'updated_by' => $actingUserId,
        ]);
        $this->activity->log('operations_tasks', 'cancelled', $actingUserId, "Cancelled task #{$id}", (string) $id);

        return ['success' => true];
    }

    public function delete(int $id, ?int $actingUserId): array
    {
        $task = $this->tasks->find($id);
        if (! $task) {
            return ['success' => false, 'error' => 'Task not found.'];
        }

        if (! in_array($task['status'], ['open', 'cancelled'], true)) {
            return ['success' => false, 'error' => 'Only open or cancelled tasks can be deleted.'];
        }

        $this->checklist->where('task_id', $id)->delete();
        $this->tasks->delete($id);
        $this->activity->log('operations_tasks', 'deleted', $actingUserId, "Deleted task #{$id}", (string) $id);

        return ['success' => true];
    }

    public function addChecklistItem(int $taskId, array $input, ?int $actingUserId): array
    {
        $task = $this->tasks->find($taskId);
        if (! $task) {
            return ['success' => false, 'errors' => ['task_id' => 'Task not found.']];
        }

        if (! in_array($task['status'], OperationsTaskModel::OPEN_STATUSES, true)) {
            return ['success' => false, 'errors' => ['status' => 'Checklist can only be edited on open tasks.']];
        }

        $title = trim((string) ($input['title'] ?? ''));
        if ($title === '') {
            return ['success' => false, 'errors' => ['title' => 'Checklist item title is required.']];
        }

        $this->checklist->insert([
            'task_id'    => $taskId,
            'title'      => $title,
            'is_done'    => 0,
            'sort_order' => $this->checklist->nextSortOrder($taskId),
        ]);

        $this->activity->log('operations_tasks', 'checklist_added', $actingUserId, "Added checklist item to task #{$taskId}", (string) $taskId);

        return ['success' => true];
    }

    public function toggleChecklistItem(int $itemId, ?int $actingUserId): array
    {
        $item = $this->checklist->find($itemId);
        if (! $item) {
            return ['success' => false, 'error' => 'Checklist item not found.'];
        }

        $task = $this->tasks->find((int) $item['task_id']);
        if ($task && ! in_array($task['status'], OperationsTaskModel::OPEN_STATUSES, true)) {
            return ['success' => false, 'error' => 'Checklist can only be edited on open tasks.'];
        }

        $newDone = empty($item['is_done']) ? 1 : 0;
        $this->checklist->update($itemId, ['is_done' => $newDone]);
        $this->activity->log(
            'operations_tasks',
            'checklist_toggled',
            $actingUserId,
            "Toggled checklist item #{$itemId} on task #{$item['task_id']}",
            (string) $item['task_id']
        );

        return ['success' => true];
    }

    public function removeChecklistItem(int $itemId, ?int $actingUserId): array
    {
        $item = $this->checklist->find($itemId);
        if (! $item) {
            return ['success' => false, 'error' => 'Checklist item not found.'];
        }

        $task = $this->tasks->find((int) $item['task_id']);
        if ($task && ! in_array($task['status'], OperationsTaskModel::OPEN_STATUSES, true)) {
            return ['success' => false, 'error' => 'Checklist can only be edited on open tasks.'];
        }

        $this->checklist->delete($itemId);
        $this->activity->log(
            'operations_tasks',
            'checklist_removed',
            $actingUserId,
            "Removed checklist item #{$itemId} from task #{$item['task_id']}",
            (string) $item['task_id']
        );

        return ['success' => true];
    }

    protected function nullableDate(mixed $value): ?string
    {
        $value = trim((string) $value);

        return $value !== '' ? $value : null;
    }
}
