<?php namespace Lucent\Edge;

use Lucent\Lexorank\Lexorank;
use Lucent\LucentException;
use Lucent\Record\InputData\EdgeInputData;

class EdgeService
{
    public function __construct(public EdgeRepo $edgeRepo)
    {
    }


    public function create(
        string $source,
        string $target,
        string $field,
        string $rank,
    ): Edge
    {


        $edge = new Edge(
            source: $source,
            target: $target,
            field: $field,
            rank: $rank,
        );
        $this->edgeRepo->insert($edge);
        return $edge;
    }

    /**
     * @param string $source
     * @param list<EdgeInputData> $edges
     * @return list<Edge>
     * @throws LucentException
     */
    public function createManyForRecord(
        string $source,
        array  $edges,
    ): array
    {
        $lastRank = Lexorank::fromString("0");
        $edgeCollection = [];
        foreach ($edges as $edge) {
            $lastRank = Lexorank::after($lastRank);
            $edgeCollection[] = new Edge(
                source: $source,
                target: $edge->target,
                field: $edge->field,
                rank: $lastRank->get(),
            );
        }

        $this->edgeRepo->insertMany($edgeCollection);
        return $edgeCollection;
    }

    /**
     * @param string $source
     * @param list<EdgeInputData> $edges
     * @return list<Edge>
     */
    public function replaceManyForRecord(
        string $source,
        array  $edges,
    ): array
    {
        $lastRank = Lexorank::fromString("0");
        $edgeCollection = [];
        foreach ($edges as $edge) {
            $lastRank = Lexorank::after($lastRank);
            $edgeCollection[] = new Edge(
                source: $source,
                target: $edge->target,
                field: $edge->field,
                rank: $lastRank->get(),
            );
        }

        $this->edgeRepo->replaceForRecord($source, $edgeCollection);
        return $edgeCollection;
    }

    public function findForSource(string $recordId): array
    {
        return $this->edgeRepo->findForSource($recordId);
    }

    public function findAll(): array
    {
        return $this->edgeRepo->findAll();
    }

    public function remove(Edge $edge): void
    {
        $this->edgeRepo->remove($edge);
    }

    private function findLastEdgeRank(string $source, string $field): string
    {
        return $this->edgeRepo->findLastEdgeRank($source, $field);
    }

}
