<?php

declare(strict_types=1);

namespace PpPhp\Core\Designer\Templates;

use PpPhp\Core\Designer\DesignerComponent as C;
use PpPhp\Core\Designer\DesignerTemplate;

abstract class FormPageTemplate extends DesignerTemplate
{
    protected int $columnsPerRow = 2;
    protected string $defaultSection = 'Basic Information';

    public function toArray(): array
    {
        return $this->basePage($this->pageTitle(), [
            $this->buildBreadcrumb(),
            $this->buildHeading(),
            $this->buildValidationSummary(),
            ...$this->buildFormSections(),
            $this->buildActionRow(),
        ]);
    }

    protected function buildBreadcrumb(): array
    {
        return C::breadcrumb('breadcrumb_main', [
            'Home',
            $this->title(),
            ucfirst($this->pageType),
        ]);
    }

    protected function buildHeading(): array
    {
        return C::heading(
            'page_heading',
            $this->pageTitle(),
            $this->pageSubtitle()
        );
    }

    protected function buildValidationSummary(): array
    {
        return C::validationSummary();
    }

    protected function buildFormSections(): array
    {
        $fields = $this->fieldsForCurrentPage();

        return [
            C::make(
                'basic_information_section',
                'section',
                'Basic Information',
                [
                    'title' => 'Basic Information',
                ],
                $this->buildRowsForFields($fields),
                [
                    'margin' => '0 0 16px 0',
                ]
            ),
        ];
    }

    protected function fieldsForCurrentPage(): array
    {
        $fields = $this->fields(1000);

        return array_values(array_filter($fields, function (array $field): bool {
            return $this->shouldShowField($field);
        }));
    }

    protected function buildRowsForFields(array $fields): array
    {
        // One CELL GRID (layout-grid) holding every field: `columnsPerRow`
        // columns, long-text fields on a full merged row. Users start from a
        // real rows×columns layout they can immediately merge/split/restyle in
        // the Designer instead of re-formatting fields from scratch. Children
        // carry tab = r*cols + c (their master cell); merged coverage lives in
        // props.cells — the exact model the Cell Grid component edits.
        $cols = max(1, min(4, $this->columnsPerRow));
        $cells = [];
        $children = [];
        $r = 0;
        $c = 0;

        foreach ($fields as $field) {
            $field = $this->normalizeField($field);
            $node = $this->buildFieldComponent($field);
            if ($this->isFullRowField($field) && $cols > 1) {
                if ($c > 0) { $r++; $c = 0; }              // start a fresh row
                $cells[$r . ':0'] = ['cs' => $cols];        // merge across the row
                $node['tab'] = $r * $cols;
                $children[] = $node;
                $r++;                                        // row fully consumed
            } else {
                $node['tab'] = $r * $cols + $c;
                $children[] = $node;
                $c++;
                if ($c >= $cols) { $r++; $c = 0; }
            }
        }

        $rows = max(1, $r + ($c > 0 ? 1 : 0));

        return [C::make(
            'form_cell_grid',
            'layout-grid',
            'Form Grid',
            // gap '' = "Match form" (see model.js formGridFor)
            ['rows' => $rows, 'cols' => $cols, 'gap' => '', 'colWidths' => '', 'cells' => $cells],
            $children
        )];
    }

    /** Long-text fields get a full merged row in the default Cell Grid. */
    protected function isFullRowField(array $field): bool
    {
        return $this->inputTypeFor($field) === 'textarea';
    }

    /** DB/type hint → the field component's inputType (drives control + build). */
    protected function inputTypeFor(array $field): string
    {
        $t = strtolower((string) ($field['type'] ?? 'text'));
        // Genuine multi-line types → textarea. NOTE: bare 'text' is the designer
        // short-input type (varchar is normalized to 'text' by the build's
        // extractFields), so it must NOT become a textarea — only the SQL
        // long-text column types do. Callers that pass a raw SQL 'text'/'tinytext'
        // column normalize it to 'textarea' first (see DesignerController).
        if (in_array($t, ['textarea', 'tinytext', 'mediumtext', 'longtext', 'json'], true)) return 'textarea';
        if (str_contains($t, 'blob')) return 'textarea';
        if (str_contains($t, 'date') || str_contains($t, 'time')) return 'date';
        if (str_contains($t, 'int') || str_contains($t, 'decimal') || str_contains($t, 'float') || str_contains($t, 'double') || str_contains($t, 'number')) return 'number';
        if (str_contains($t, 'enum') || $t === 'select') return 'select';
        if (str_contains($t, 'bool') || $t === 'tinyint(1)') return 'checkbox';
        return 'text';
    }

    protected function buildRow(int $rowNumber, array $cells): array
    {
        return C::make(
            'form_row_' . $rowNumber,
            'row',
            'Form Row ' . $rowNumber,
            [
                'columns' => count($cells),
                'cells' => $cells,
            ],
            [],
            [
                'margin' => '0 0 12px 0',
            ]
        );
    }

    protected function buildFieldComponent(array $field): array
    {
        $fieldName = $field['name'];

        return C::make(
            C::safeId($fieldName . '_field'),
            'field',
            $field['label'],
            [
                'field' => $fieldName,
                'label' => $field['label'],
                'required' => $field['required'],
                'readonly' => $this->isReadonly(),
                'type' => $field['type'],
                'inputType' => $this->inputTypeFor($field),
                'mode' => $this->pageType === 'view' ? 'view' : 'edit',
                'placeholder' => $field['placeholder'],
                'defaultValue' => $field['defaultValue'],
                'helpText' => $field['helpText'],
                'formMode' => $this->pageType,
                'rules' => [
                    'visibleWhen' => $field['visibleWhen'],
                    'readonlyWhen' => $field['readonlyWhen'],
                    'requiredWhen' => $field['requiredWhen'],
                ],
            ],
            [],
            [],
            C::events([
                'context' => '$field->getCurrentRecord()',
            ])
        );
    }

    protected function buildActionRow(): array
    {
        // A REAL `buttons` component — the form walker's `case 'buttons'`
        // renders it, so builds honour these keys (and any buttonConfig)
        // instead of silently appending the generic Save/Cancel fallback.
        // The legacy layout row kept its button-group in cells[].components,
        // which the child walker never visits, so it rendered nothing.
        return C::make(
            'form_actions',
            'buttons',
            'Form Actions',
            [
                'buttons' => $this->buttonKeys(),
                'buttonConfig' => [],
            ]
        );
    }

    /** Button KEYS understood by the build's renderFormButtons, per page type. */
    protected function buttonKeys(): array
    {
        return match ($this->pageType) {
            'add' => ['save', 'save_new', 'cancel'],
            'edit' => ['save', 'cancel', 'back'],
            'view', 'print' => ['back'],
            default => ['save', 'cancel'],
        };
    }

    protected function normalizeField(array $field): array
    {
        $name = (string) (
            $field['name']
            ?? $field['field']
            ?? $field['fieldName']
            ?? $field['column']
            ?? 'field'
        );

        return array_merge([
            'name' => $name,
            'label' => $this->fieldLabel(['name' => $name] + $field),
            'type' => 'text',
            'required' => false,
            'placeholder' => '',
            'defaultValue' => '',
            'helpText' => '',
            'visibleWhen' => '',
            'readonlyWhen' => '',
            'requiredWhen' => '',
        ], $field, [
            'name' => $name,
            'label' => $field['label'] ?? ucwords(str_replace('_', ' ', $name)),
        ]);
    }

    protected function shouldShowField(array $field): bool
    {
        if (($field['enabled'] ?? true) === false) {
            return false;
        }

        if (isset($field['showOn']) && is_array($field['showOn'])) {
            return (bool) ($field['showOn'][$this->pageType] ?? true);
        }

        $legacyKey = 'showOn' . ucfirst($this->pageType);

        return (bool) ($field[$legacyKey] ?? true);
    }

    protected function fieldSpan(array $field, int $defaultSpan): int
    {
        if (isset($field['formSpan'])) {
            return max(1, min(12, (int) $field['formSpan']));
        }

        $type = strtolower((string) ($field['type'] ?? ''));

        if (in_array($type, ['textarea', 'longtext', 'json'], true)) {
            return 12;
        }

        return $defaultSpan;
    }

    protected function isReadonly(): bool
    {
        return false;
    }

    protected function pageTitle(): string
    {
        return ucfirst($this->pageType) . ' ' . $this->title();
    }

    protected function pageSubtitle(): string
    {
        return '';
    }
}
