<?php

namespace modules\selfserve\classes;

require_once WD . '/classes/attachments.php';
require_once WD . '/classes/attachment_store.php';

use classes\attachments;
use classes\attachment_store;

class selfserve_task_attachment_payloads
{
    private const OBJECT_TYPE = 'department_selfserve_tasks';

    /**
     * @param array<int,array<string,mixed>> $tasks
     * @return array<int,array<string,mixed>>
     */
    public function attachToTasks(array $tasks): array
    {
        if ($tasks === []) {
            return [];
        }

        $taskIds = [];
        foreach ($tasks as $task) {
            if (!is_array($task)) {
                continue;
            }
            $taskId = $this->taskObjectId($task);
            if ($taskId !== null) {
                $taskIds[] = $taskId;
            }
        }

        $attachmentsByTask = [];
        if ($taskIds !== []) {
            try {
                $attachmentsByTask = (new attachments())->listMany(self::OBJECT_TYPE, $taskIds);
            } catch (\Throwable) {
                $attachmentsByTask = [];
            }
        }

        $store = new attachment_store();
        return array_values(array_map(function (array $task) use ($attachmentsByTask, $store): array {
            $taskId = $this->taskObjectId($task);
            $attachments = [];

            if ($taskId !== null && isset($attachmentsByTask[$taskId])) {
                foreach ((array)$attachmentsByTask[$taskId] as $attachment) {
                    if (is_object($attachment)) {
                        $attachments[] = $this->formatAttachment($attachment, $store);
                    }
                }
            } elseif (isset($task['attachments']) && is_array($task['attachments'])) {
                $attachments = array_values($task['attachments']);
            }

            $task['attachments'] = $attachments;
            return $task;
        }, $tasks));
    }

    /**
     * @param array<string,mixed> $task
     */
    private function taskObjectId(array $task): ?int
    {
        $taskId = (int)($task['id'] ?? $task['task_id'] ?? 0);
        return $taskId > 0 ? $taskId : null;
    }

    /**
     * @return array<string,mixed>
     */
    private function formatAttachment(object $attachment, attachment_store $store): array
    {
        $content = $this->contentPayload($attachment->content ?? null);
        $fileName = $content['document'] ?: $content['image'] ?: null;

        return [
            'id' => isset($attachment->id) ? (int)$attachment->id : null,
            'object_type' => isset($attachment->object_type) ? (string)$attachment->object_type : self::OBJECT_TYPE,
            'object_id' => isset($attachment->object_id) ? (int)$attachment->object_id : null,
            'content' => $content,
            'download_link' => is_string($fileName) && trim($fileName) !== ''
                ? $store->generateDirectDownloadUrl($fileName)
                : null,
            'created_at' => isset($attachment->created_at) ? (string)$attachment->created_at : null,
            'updated_at' => isset($attachment->updated_at) ? (string)$attachment->updated_at : null,
        ];
    }

    /**
     * @return array{image: ?string, document: ?string, relation: mixed, other: mixed}
     */
    private function contentPayload(mixed $content): array
    {
        $payload = is_object($content) && method_exists($content, 'toArray')
            ? $content->toArray()
            : (is_array($content) ? $content : (array)$content);

        $relation = $payload['relation'] ?? null;
        if (is_object($relation) && method_exists($relation, 'toArray')) {
            $relation = $relation->toArray();
        } elseif (is_object($relation)) {
            $relation = (array)$relation;
        }

        return [
            'image' => isset($payload['image']) && is_string($payload['image']) ? $payload['image'] : null,
            'document' => isset($payload['document']) && is_string($payload['document']) ? $payload['document'] : null,
            'relation' => $relation,
            'other' => $payload['other'] ?? null,
        ];
    }
}
