<?php

declare(strict_types=1);

namespace App\Framework\Database\Schema\Index;

/**
 * SQLite-specific index functionality
 */
final class SQLiteIndex
{
    /**
     * @var AdvancedIndexDefinition The underlying index definition
     */
    private AdvancedIndexDefinition $definition;

    /**
     * Create a new SQLite index
     */
    private function __construct(AdvancedIndexDefinition $definition)
    {
        $this->definition = $definition;
    }

    /**
     * Create a standard index
     *
     * @param string|null $name The name of the index
     * @param array<string> $columns The columns to index
     * @return self
     */
    public static function create(?string $name, array $columns): self
    {
        return new self(AdvancedIndexDefinition::create($name, $columns, AdvancedIndexType::INDEX));
    }

    /**
     * Create a unique index
     *
     * @param string|null $name The name of the index
     * @param array<string> $columns The columns to index
     * @return self
     */
    public static function unique(?string $name, array $columns): self
    {
        return new self(AdvancedIndexDefinition::create($name, $columns, AdvancedIndexType::UNIQUE));
    }

    /**
     * Create a partial index with a WHERE clause
     *
     * @param string|null $name The name of the index
     * @param array<string> $columns The columns to index
     * @param string $whereClause The WHERE clause for the partial index
     * @param bool $unique Whether the index is unique
     * @return self
     */
    public static function partial(
        ?string $name,
        array $columns,
        string $whereClause,
        bool $unique = false
    ): self {
        $type = $unique ? AdvancedIndexType::UNIQUE : AdvancedIndexType::INDEX;

        return new self(AdvancedIndexDefinition::partial($name, $columns, $type, $whereClause));
    }

    /**
     * Set the index to be created IF NOT EXISTS
     *
     * @return self
     */
    public function ifNotExists(): self
    {
        $this->definition->options['if_not_exists'] = true;

        return $this;
    }

    /**
     * Generate SQL for this index
     *
     * @param string $table The table name
     * @return string The SQL statement
     */
    public function toSql(string $table): string
    {
        $sql = $this->definition->toSql('sqlite', $table);

        // Add IF NOT EXISTS if specified
        if (isset($this->definition->options['if_not_exists']) && $this->definition->options['if_not_exists']) {
            $sql = str_replace('CREATE INDEX', 'CREATE INDEX IF NOT EXISTS', $sql);
            $sql = str_replace('CREATE UNIQUE INDEX', 'CREATE UNIQUE INDEX IF NOT EXISTS', $sql);
        }

        return $sql;
    }

    /**
     * Get the underlying index definition
     */
    public function getDefinition(): AdvancedIndexDefinition
    {
        return $this->definition;
    }
}
