<?php

declare(strict_types=1);

namespace apexl\Io\dto\Relationship;

use apexl\entityCore\collections\EntityCollection;
use apexl\Io\dto\LoaderCondition;
use apexl\Io\includes\Entity;
use apexl\Io\interfaces\RelationshipInterface;
use apexl\Utils\Class\ClassBasename;
use apexl\Utils\Strings\Pluralizer;
use Closure;
use Stringy\Stringy;

final readonly class BelongsTo extends OneToOne
{
    /** @param class-string<Entity> $remoteEntity */
    public static function create(
        string $name,
        Entity $localEntity,
        string $remoteEntity,
        null|array|string $localKey = null,
        null|array|string $remoteKey = null,
        ?RelationshipInterface $parent = null,
        ?Closure $queryCallback = null,
        ?Closure $rawJoin = null,
        ?Closure $rawQuery = null,
        ?string $aliasedRemoteTable = null,
    ): self {
        return new self(
            name: $name,
            localEntity: $localEntity,
            remoteEntity: $remoteEntity,
            localTable: $localEntity->getTableName(),
            localKey: $localKey ?? $localEntity->getPrimaryKey(),
            remoteKey: $remoteKey ?? self::remoteKey($localEntity),
            parent: $parent,
            aliasedRemoteTable: $aliasedRemoteTable,
            queryCallback: $queryCallback,
            rawJoin: $rawJoin,
            rawQuery: $rawQuery,
        );
    }

    private static function remoteKey(Entity $localEntity): string
    {
        return Pluralizer::singular(
            Stringy::create(ClassBasename::classBasename($localEntity::class))
                ->snakeize()
                ->append('_id')
                ->toString()
        );
    }

    public function set(int|array|EntityCollection|Entity $entity): void
    {
        $this->assertSetType($entity);

        $localEntityId = $this->localEntity->{$this->localEntity->getPrimaryKey()};

        $this->clear();

        $entity = $this->ensureEntity($entity);

        $this->localEntity->{$this->name} = $entity;

        $entity->{$this->getRemoteKey()} = $localEntityId;
        $entity->store();
    }

    public function clear(): void
    {
        $localEntityId = $this->localEntity->{$this->localEntity->getPrimaryKey()};

        $this->remoteEntity::findMultiple([
            LoaderCondition::equals($this->getRemoteKey(), $localEntityId),
        ])->each(function (Entity $entity) {
            $entity->{$this->getRemoteKey()} = null;
            $entity->store();
        });

        $this->localEntity->{$this->name} = $this->valueWhenEmpty();
    }
}


