<?php

declare(strict_types=1);

namespace System\Database;

final class Blueprint
{
    private string $table;

    /**
     * @var ColumnDefinition[]
     */
    private array $columns = [];

    public function __construct(string $table)
    {
        $this->table = $table;
    }

    public function id(): self
    {
        $column = new ColumnDefinition('id', 'BIGINT UNSIGNED');

        $column->primary = true;
        $column->autoIncrement = true;

        $this->columns[] = $column;

        return $this;
    }

    public function string(
        string $name,
        int $length = 255
    ): ColumnDefinition {

        $column = new ColumnDefinition(
            $name,
            'VARCHAR',
            $length
        );

        $this->columns[] = $column;

        return $column;
    }

    public function integer(
        string $name
    ): ColumnDefinition {

        $column = new ColumnDefinition(
            $name,
            'INT'
        );

        $this->columns[] = $column;

        return $column;
    }

    public function boolean(
        string $name
    ): ColumnDefinition {

        $column = new ColumnDefinition(
            $name,
            'TINYINT(1)'
        );

        $column->default = 0;

        $this->columns[] = $column;

        return $column;
    }

    public function foreignId(
        string $name
    ): ColumnDefinition {

        $column = new ColumnDefinition(
            $name,
            'BIGINT UNSIGNED'
        );

        $this->columns[] = $column;

        return $column;
    }

    public function timestamps(): self
    {
        $this->columns[] =
            new ColumnDefinition(
                'created_at',
                'TIMESTAMP'
            );

        $this->columns[] =
            new ColumnDefinition(
                'updated_at',
                'TIMESTAMP'
            );

        return $this;
    }

    public function toSql(): string
    {
        $sql = [];

        foreach ($this->columns as $column) {

            $line = "{$column->name} {$column->type}";

            if ($column->length !== null) {
                $line .= "({$column->length})";
            }

            if (!$column->nullable) {
                $line .= " NOT NULL";
            }

            if ($column->default !== null) {

                $value = is_bool($column->default)
                    ? (int)$column->default
                    : $column->default;

                $line .= " DEFAULT '{$value}'";
            }

            if ($column->autoIncrement) {
                $line .= " AUTO_INCREMENT";
            }

            if ($column->primary) {
                $line .= " PRIMARY KEY";
            }

            if ($column->unique) {
                $line .= " UNIQUE";
            }

            $sql[] = $line;
        }

        foreach ($this->columns as $column) {

            if ($column->on !== null) {

                $sql[] =
                    "FOREIGN KEY ({$column->name}) REFERENCES {$column->on}({$column->references})";

            }

        }

        return sprintf(
            "CREATE TABLE %s (%s)",
            $this->table,
            implode(', ', $sql)
        );
    }
}