<?php

namespace Velis\Dto\RelationTransformer;

use Attribute;
use InvalidArgumentException;
use Velis\Dto\BaseDto;
use Velis\Model\DataObject;
use Velis\Model\RelationLoader\Exceptions\NotLoadedRelationException;

/**
 * This Attribute is responsible for transforming related models to the specified DTOs.
 * @author Szymon Janaczek <szymon.janaczek@velistech.com>
 * @template TTargetClass
 */
#[Attribute]
class Relation implements RelationTransformer
{
    /**
     * @param class-string<TTargetClass> $targetClass
     */
    public function __construct(
        public string $targetClass,
        public string $relationName,
        public ?array $onlyFields = null
    ) {
        if (!class_exists($targetClass)) {
            throw new InvalidArgumentException("Class `$targetClass` does not exist.");
        }
    }

    /**
     * @throws NotLoadedRelationException
     */
    public function map(DataObject $model): BaseDto|array|null
    {
        if (!$model->hasRelation($this->relationName)) {
            return null;
        }

        $relatedData = $model->getRelation($this->relationName);

        if (is_array($relatedData)) {
            return array_map(
                fn ($item) => $this->createDto($item),
                $relatedData
            );
        }

        if ($relatedData instanceof DataObject) {
            return $this->createDto($relatedData);
        }

        return null;
    }

    protected function createDto(DataObject $model): BaseDto
    {
        $dto = $this->targetClass::fromModel($model);
        if ($this->onlyFields !== null) {
            $dto->only($this->onlyFields);
        }
        return $dto;
    }
}
