<?php

namespace App\Element;

use App\Set\Set as DomainSet;
use App\Set\SetRepository;
use DomainException;

class EloquentElementRepository implements ElementRepository
{
    public function __construct(private SetRepository $setRepo)
    {
    }

    public function create(CreateElementDto $dto): Element
    {
        $model = ElementModel::create([
            'set_id' => $dto->set->getId(),
            'title' => $dto->title,
            'parent_element_id' => $dto->parentElement?->getId(),
        ]);

        return new Element(
            id: $model->id,
            title: $dto->title,
            set: $dto->set,
            parentElement: $dto->parentElement,
        );
    }

    public function find(int $id): ?Element
    {
        $model = ElementModel::find($id);

        return $model === null ? null : $this->toDomain($model);
    }

    /**
     * @return Element[]
     */
    public function findBySet(DomainSet $set): array
    {
        $models = ElementModel::where('set_id', $set->getId())
            ->orderBy('id')
            ->get();
        $elements = [];
        foreach ($models as $model) {
            $elements[] = $this->toDomain($model);
        }

        return $elements;
    }

    private function toDomain(ElementModel $model): Element
    {
        $set = $this->setRepo->find($model->set_id);
        if ($set === null) {
            throw new DomainException(
                "Set with id: {$model->set_id} doesnt exist"
            );
        }

        $parentElement = null;
        if ($model->parent_element_id !== null) {
            $parentElement = $this->find($model->parent_element_id);
            if ($parentElement === null) {
                throw new DomainException(
                    "Element with id: {$model->parent_element_id} doesnt exist"
                );
            }
        }

        return new Element(
            id: $model->id,
            title: $model->title,
            set: $set,
            parentElement: $parentElement,
        );
    }
}
