<?php

declare(strict_types=1);

namespace PpPhp\Core\Designer;

abstract class DesignerTemplate
{
    protected string $table;
    protected string $pageType;
    protected array $fields;
    protected array $options;

    public function __construct(string $table, string $pageType, array $fields = [], array $options = [])
    {
        $this->table = $table;
        $this->pageType = $pageType;
        $this->fields = array_values(array_filter($fields, fn($f) => ($f['enabled'] ?? true) !== false));
        $this->options = $options;
    }

    abstract public function toArray(): array;

    protected function title(?string $suffix = null): string
    {
        $title = $this->table !== ''
            ? ucwords(str_replace('_', ' ', $this->table))
            : ucwords(str_replace('_', ' ', $this->pageType));

        return $suffix ? trim($title . ' ' . $suffix) : $title;
    }

    protected function basePage(string $title, array $components): array
    {
        $safeTable = $this->table !== '' ? DesignerComponent::safeId($this->table) : 'app';

        return [
            'id' => $safeTable . '_' . DesignerComponent::safeId($this->pageType),
            'name' => $this->pageType,
            'type' => $this->pageType,
            'title' => $title,
            'layout' => [
                'device' => 'desktop',
                'width' => 'fluid',
                'theme' => 'simple',
                'align' => 'left',
            ],
            'settings' => [
                'customCss' => '',
                'customJs' => '',
                'locked' => false,
            ],
            'components' => $components,
        ];
    }

    protected function fields(int $limit = 0): array
    {
        $fields = $this->fields;

        if (empty($fields)) {
            $fields = [
                ['name' => 'id', 'label' => 'ID', 'type' => 'int'],
                ['name' => 'name', 'label' => 'Name', 'type' => 'varchar'],
                ['name' => 'created_at', 'label' => 'Created At', 'type' => 'datetime'],
            ];
        }

        // $limit <= 0 means "all fields" — a scaffold must never silently drop
        // columns the user marked visible in the Fields module.
        return $limit > 0 ? array_slice($fields, 0, $limit) : $fields;
    }

    /**
     * Fields the user marked visible for a given page ('list', 'add', 'edit',
     * 'view', …) via the Fields module. A field opts OUT only by an explicit
     * false flag; an unset flag defaults to visible. If NONE are flagged (a
     * table configured with no per-page choices), every field is returned so the
     * scaffold is never empty.
     *
     * @return array<int,array<string,mixed>>
     */
    protected function pageFields(string $page): array
    {
        $all = $this->fields();
        $picked = array_values(array_filter(
            $all,
            static function (array $f) use ($page): bool {
                if (($f['enabled'] ?? true) === false) {
                    return false;
                }
                // Per-page visibility arrives in two shapes: `showOn` (build-time
                // synthesis via BuildWriter::templateFieldsFor / TemplateFactory —
                // same shape FormPageTemplate reads) or `pages` (the Designer's
                // Reset-to-Default endpoint). Honour whichever is present; a field
                // opts OUT only via an explicit false, an unset flag stays visible.
                if (isset($f['showOn']) && is_array($f['showOn'])) {
                    return ($f['showOn'][$page] ?? true) !== false;
                }
                return (($f['pages'][$page] ?? true) !== false);
            }
        ));
        return $picked !== [] ? $picked : $all;
    }

    protected function fieldLabel(array $field): string
    {
        $name = (string)($field['name'] ?? 'field');
        return (string)($field['label'] ?? ucwords(str_replace('_', ' ', $name)));
    }

    /**
     * Apply the project's app brand (Style → Layout → Logo, passed in via
     * options 'brand' / 'brandImage') to an auth-template prop map: overrides
     * brandName/brandMark, carries the logo image, and rewrites the persona
     * placeholder names (Northstar/Lumina/Atlas) inside copy strings like
     * "Sign in to Atlas" so every template speaks the real app name.
     */
    protected function applyBrand(array $props): array
    {
        $brand = trim((string) ($this->options['brand'] ?? ''));
        $image = trim((string) ($this->options['brandImage'] ?? ''));

        if ($brand !== '') {
            $props = array_map(
                static fn ($v) => is_string($v) ? str_replace(['PPPHP', 'Northstar', 'Lumina', 'Atlas', 'Evergreen'], $brand, $v) : $v,
                $props
            );
            $props['brandName'] = $brand;
            $props['brandMark'] = mb_strtoupper(mb_substr($brand, 0, 1));
        }
        if ($image !== '') {
            $props['brandImage'] = $image;
        }

        return $props;
    }
}
