<?php namespace Lucent\Edge;

use Lucent\Database\Database;
use Lucent\LucentException;
use PDOException;
use stdClass;

class EdgeRepo
{

    public function __construct()
    {
    }

    public function insert(Edge $edge): void
    {
        try {
            Database::make()->table("edges")->insert($edge->toDB());
        } catch (PDOException $e) {
            if ($e->getCode() == 23505) {
                throw new LucentException("Edge already exists");
            }
            throw $e;
        }

    }

    /**
     * @param list<Edge> $edges
     * @return void
     * @throws LucentException
     */
    public function insertMany(array $edges): void
    {
        $edgesDB = collect($edges)->map(fn($e) => $e->toDB())->toArray();
        try {
            Database::make()->table("edges")->insert($edgesDB);
        } catch (PDOException $e) {
            if ($e->getCode() == 23505) {
                throw new LucentException("Edge already exists");
            }
            throw $e;
        }

    }

    /**
     * @param string $from
     * @param list<Edge> $edges
     * @return void
     */
    public function replaceForRecord(string $from, array $edges): void
    {
        $edgesDB = collect($edges)->map(fn($e) => $e->toDB())->toArray();
        Database::make()->table("edges")->where("source", $from)->delete();
        Database::make()->table("edges")->insert($edgesDB);
    }


    /**
     * @return list<Edge>
     */
    public function findAll(): array
    {
        $edges = Database::make()->table("edges")->get();
        return $edges->map([$this, 'mapEdge'])->toArray();
    }

    public function findForSource(string $recordId): array
    {
        $edges = Database::make()->table("edges")->where("source", $recordId)->get();
        return $edges->map([$this, 'mapEdge'])->toArray();
    }

    public function mapEdge(stdClass $edge): Edge
    {

        return new Edge(
            source: $edge->source,
            target: $edge->target,
            sourceSchema: $edge->sourceSchema,
            targetSchema: $edge->targetSchema,
            field: $edge->field,
            rank: $edge->rank,
            depth: $edge->depth ?? 0
        );

    }

    public function remove(Edge $edge): void
    {
        Database::make()->table("edges")
            ->where("source", $edge->source)
            ->where("target", $edge->target)
            ->where("sourceSchema", $edge->sourceSchema)
            ->where("targetSchema", $edge->targetSchema)
            ->where("field", $edge->field)
            ->delete();
    }

    public function findLastEdgeRank(string $source, string $field): string
    {
        $data = Database::make()->table("edges")
            ->where("source", $source)
            ->where("field", $field)
            ->orderBy("rank", "desc")
            ->first();

        return $data->rank ?? "";
    }

}
