<?php

declare(strict_types=1);

namespace App\Framework\Database\Schema;

use App\Framework\Database\ValueObjects\ColumnName;
use App\Framework\Database\ValueObjects\ConstraintName;
use App\Framework\Database\ValueObjects\TableName;

final class ForeignKeyDefinition
{
    /** @var array<ColumnName> */
    public readonly array $columns;

    public ?TableName $referencedTable = null;

    /** @var array<ColumnName> */
    public array $referencedColumns = [];

    public ForeignKeyAction $onUpdate = ForeignKeyAction::RESTRICT;

    public ForeignKeyAction $onDelete = ForeignKeyAction::RESTRICT;

    public ?ConstraintName $name = null;

    /**
     * @param array<string|ColumnName> $columns
     */
    public function __construct(array $columns)
    {
        $this->columns = array_map(
            fn($col) => $col instanceof ColumnName ? $col : ColumnName::fromString($col),
            $columns
        );
    }

    /**
     * @param string|ColumnName|array<string|ColumnName> $columns
     */
    public function references(string|ColumnName|array $columns): self
    {
        $columnsArray = is_array($columns) ? $columns : [$columns];

        $this->referencedColumns = array_map(
            fn($col) => $col instanceof ColumnName ? $col : ColumnName::fromString($col),
            $columnsArray
        );

        return $this;
    }

    public function on(string|TableName $table): self
    {
        $this->referencedTable = $table instanceof TableName ? $table : TableName::fromString($table);

        return $this;
    }

    public function onUpdate(ForeignKeyAction $action): self
    {
        $this->onUpdate = $action;

        return $this;
    }

    public function onDelete(ForeignKeyAction $action): self
    {
        $this->onDelete = $action;

        return $this;
    }

    public function cascadeOnUpdate(): self
    {
        return $this->onUpdate(ForeignKeyAction::CASCADE);
    }

    public function cascadeOnDelete(): self
    {
        return $this->onDelete(ForeignKeyAction::CASCADE);
    }

    public function nullOnDelete(): self
    {
        return $this->onDelete(ForeignKeyAction::SET_NULL);
    }

    public function restrictOnDelete(): self
    {
        return $this->onDelete(ForeignKeyAction::RESTRICT);
    }

    public function name(string|ConstraintName $name): self
    {
        $this->name = $name instanceof ConstraintName ? $name : ConstraintName::fromString($name);

        return $this;
    }
}
