<?php

namespace Wizard\MagicForger\Replacer;

trait TableReplacer
{
    protected ?array $columns = null;

    protected array $columns_to_ignore = [
        'id',
        'created_at',
        'updated_at',
        'created_by',
        'updated_by',
        'deleted_at',
    ];

    /**
     * Retrieve columns for the current table.
     */
    protected function get_columns(): array
    {
        if (is_null($this->columns)) {
            $this->columns = $this->getTableColumns($this->getCurrentTable());
        }

        return $this->columns;
    }

    /**
     * Get a string representation of values for creation.
     */
    protected function getValuesForCreation(): string
    {
        $insert = '';
        foreach ($this->get_columns() as $column) {
            $column_name = $column['name'];
            $insert .= sprintf('$item->%s = $validated["%s"] ?? NULL;', $column_name, $column_name)."\n";
        }

        return $insert;
    }

    /**
     * Get a string representation of table attributes.
     */
    protected function getCasts(): string
    {
        $insert = '';
        foreach ($this->get_columns() as $column) {
            if (in_array($column['name'], $this->columns_to_ignore)) {
                continue;
            }
            $type = $column['type_name'];
            // date
            if (in_array($type, ['date'])) {
                $insert .= sprintf("'%s' => 'date:Y-m-d',", $column['name'])."\n";
            }
            // time
            if (in_array($type, ['timestamp'])) {
                $insert .= sprintf("'%s' => 'date:Y-m-d H:i',", $column['name'])."\n";
            }
        }

        return $insert;
    }

    /**
     * Get a string representation of table attributes.
     */
    protected function getAttributes(): string
    {
        $insert = '';
        foreach ($this->get_columns() as $column) {
            if (in_array($column['name'], $this->columns_to_ignore)) {
                continue;
            }
            $insert .= sprintf("'%s' => '',", $column['name'])."\n";
        }

        return $insert;
    }

    /**
     * Get a string representation of table fillable columns.
     */
    protected function getFillable(): string
    {
        $insert = '';
        foreach ($this->get_columns() as $column) {
            if (in_array($column['name'], $this->columns_to_ignore)) {
                continue;
            }
            $insert .= sprintf("'%s',", $column['name'])."\n";
        }

        return $insert;
    }

    /**
     * Get formatted validation rules for table columns.
     */
    protected function getValuesForValidation(): string
    {
        $insert = '';
        foreach ($this->get_columns() as $column) {
            // Don't do validation on some of the basic columns
            if (in_array($column['name'], $this->columns_to_ignore)) {
                continue;
            }

            $options = [];

            // Add default value checks if needed
            if (is_null($column['default']) && ! $column['nullable']) {
                $options[] = "'required'";
            }
            else {
                $options[] = "'nullable'";
            }

            // Determine the validations based on column type
            $type = strtolower($column['type_name']);
            $size = (preg_match('/\((\d+)\)/', $column['type'], $matches)) ? $matches[1] : null;

            switch ($type) {
                case 'varchar':
                case 'char':
                    $options[] = "'string'";

                    // Extract length if defined
                    if (! is_null($size)) {
                        $options[] = "'max:$size'";
                    }
                    break;

                case 'text':
                    $options[] = "'string'";
                    break;

                case 'int':
                case 'tinyint':
                case 'smallint':
                case 'mediumint':
                case 'bigint':
                    $options[] = "'integer'";
                    if (strpos($column['type'], 'unsigned') !== false) {
                        $options[] = "'min:0'";
                    }
                    if (! is_null($size)) {
                        $options[] = "'max_digits:".$size."'";
                    }
                    break;

                case 'decimal':
                case 'double':
                case 'float':
                    $options[] = "'numeric'";
                    // Extract precision and scale if defined
                    if (preg_match('/\((\d+),(\d+)\)/', $column['type'], $matches)) {
                        $precision = $matches[1];
                        $scale = isset($matches[2]) ? ','.$matches[2] : '';

                        $options[] = "'decimal:$precision$scale'";
                    }
                    break;

                case 'boolean':
                    $options[] = "'boolean'";
                    break;

                case 'date':
                case 'datetime':
                case 'timestamp':
                    $options[] = "'date'";
                    break;

                    // Add other types as needed
            }

            $insert .= sprintf("'%s' => [%s],\n", $column['name'], implode(',', $options));
        }

        return $insert;
    }

    /**
     * Apply insertions in the target template.
     */
    public function apply_inserts(string $target): string
    {
        $inserts = $this->get_all_keywords($target);
        $available_insertions = $this->get_available_inserts();

        return str_replace(
            array_keys($available_insertions),
            $available_insertions,
            $target
        );
    }

    /**
     * Get available insertion points for the template.
     */
    public function get_available_inserts(): array
    {
        return [
            '// {{ valuesForCreation }}' => $this->getValuesForCreation(),
            '# {{ attributeInsertPoint }}' => $this->getAttributes(),
            '# {{ castInsertPoint }}' => $this->getCasts(),
            '# {{ fillableInsertPoint }}' => $this->getFillable(),
            '// {{ valuesForValidation }}' => $this->getValuesForValidation(),
        ];
    }
}
