<?php

declare(strict_types=1);

namespace App\Framework\Database\Platform\ValueObjects;

use App\Framework\Database\Platform\Enums\IndexType;

/**
 * Represents a database index definition
 */
final readonly class IndexDefinition
{
    public function __construct(
        public string $name,
        public IndexType $type,
        public array $columns,
        public ?string $tableName = null,
        public array $options = []
    ) {
        if (empty($columns)) {
            throw new \InvalidArgumentException('Index must have at least one column');
        }

        foreach ($columns as $column) {
            if (! is_string($column) || trim($column) === '') {
                throw new \InvalidArgumentException('All index columns must be non-empty strings');
            }
        }
    }

    public static function primary(string $name = 'PRIMARY', array $columns = ['id']): self
    {
        return new self($name, IndexType::PRIMARY, $columns);
    }

    public static function unique(string $name, array $columns): self
    {
        return new self($name, IndexType::UNIQUE, $columns);
    }

    public static function index(string $name, array $columns): self
    {
        return new self($name, IndexType::INDEX, $columns);
    }

    public static function fulltext(string $name, array $columns): self
    {
        return new self($name, IndexType::FULLTEXT, $columns);
    }

    public static function spatial(string $name, array $columns): self
    {
        return new self($name, IndexType::SPATIAL, $columns);
    }

    public function withTable(string $tableName): self
    {
        return new self(
            name: $this->name,
            type: $this->type,
            columns: $this->columns,
            tableName: $tableName,
            options: $this->options
        );
    }

    public function withOptions(array $options): self
    {
        return new self(
            name: $this->name,
            type: $this->type,
            columns: $this->columns,
            tableName: $this->tableName,
            options: array_merge($this->options, $options)
        );
    }

    public function getFullName(): string
    {
        if ($this->tableName) {
            return "{$this->tableName}_{$this->name}";
        }

        return $this->name;
    }

    public function isComposite(): bool
    {
        return count($this->columns) > 1;
    }

    public function getFirstColumn(): string
    {
        return $this->columns[0];
    }

    public function getColumnsString(): string
    {
        return implode(', ', $this->columns);
    }
}
