<?php

declare(strict_types=1);

namespace PpPhp\Core\Designer\Renderer;

final class DesignerRenderer
{
    public function renderPage(array $page): string
    {
        $components = (array) ($page['components'] ?? []);
        $title = htmlspecialchars((string) ($page['title'] ?? 'Page'), ENT_QUOTES, 'UTF-8');

        if ($components === []) {
            return $this->emptyPage($title);
        }

        $html = '<div class="ppd-page" data-designer-page="' . htmlspecialchars((string) ($page['id'] ?? ''), ENT_QUOTES, 'UTF-8') . '">';
        foreach ($components as $component) {
            if (is_array($component)) {
                $html .= $this->renderComponent($component);
            }
        }
        $html .= '</div>';

        return $html;
    }

    public function renderComponent(array $component): string
    {
        $node = DesignerRenderNode::fromArray($component);

        return match ($node->type()) {
            'breadcrumb' => $this->breadcrumb($node),
            'heading' => $this->heading($node),
            'button', 'action_button' => $this->button($node),
            'button_group' => $this->buttonGroup($node),
            'table_grid', 'data_grid', 'grid' => $this->tableGrid($node),
            'pagination' => $this->pagination($node),
            'section' => $this->section($node),
            'row' => $this->row($node),
            default => $this->generic($node),
        };
    }

    private function emptyPage(string $title): string
    {
        return '<div class="ppd-page ppd-page-empty">'
            . '<div class="ppd-empty-state">'
            . '<div class="ppd-empty-title">' . $title . '</div>'
            . '<div class="ppd-empty-text">Add components from the left panel to design this page.</div>'
            . '</div>'
            . '</div>';
    }

    private function breadcrumb(DesignerRenderNode $node): string
    {
        $items = (array) ($node->props()['items'] ?? ['Home', $node->label()]);
        $html = $this->open($node, 'nav', 'ppd-breadcrumb');
        foreach ($items as $index => $item) {
            $html .= '<span class="ppd-breadcrumb-item' . ($index === array_key_last($items) ? ' active' : '') . '">' . $this->esc((string) $item) . '</span>';
        }
        return $html . '</nav>';
    }

    private function heading(DesignerRenderNode $node): string
    {
        $level = max(1, min(6, (int) ($node->props()['level'] ?? 2)));
        return $this->open($node, 'h' . $level, 'ppd-heading') . $this->esc($node->label()) . '</h' . $level . '>';
    }

    private function button(DesignerRenderNode $node): string
    {
        $variant = $this->esc((string) ($node->props()['variant'] ?? 'primary'));
        $text = $this->esc((string) ($node->props()['text'] ?? $node->label()));
        $icon = (string) ($node->props()['icon'] ?? '');

        return $this->open($node, 'button', 'ppd-btn ppd-btn-' . $variant)
            . ($icon !== '' ? '<i class="' . $this->esc($icon) . '"></i> ' : '')
            . $text
            . '</button>';
    }

    private function buttonGroup(DesignerRenderNode $node): string
    {
        $buttons = (array) ($node->props()['buttons'] ?? []);
        $html = $this->open($node, 'div', 'ppd-button-group');
        foreach ($buttons as $button) {
            if (is_array($button)) {
                $html .= $this->button(DesignerRenderNode::fromArray(array_replace([
                    'id' => $node->id() . '_btn',
                    'type' => 'button',
                    'label' => 'Button',
                    'props' => [],
                ], $button)));
            }
        }
        return $html . '</div>';
    }

    private function tableGrid(DesignerRenderNode $node): string
    {
        $props = $node->props();
        $columns = (array) ($props['columns'] ?? []);
        $actions = (array) ($props['actions'] ?? []);
        $bulkActions = (array) ($props['bulkActions'] ?? []);
        $showSearch = (bool) ($props['search'] ?? true);
        $showAdd = (bool) ($props['addButton'] ?? true);

        if ($columns === []) {
            $columns = [
                ['field' => 'id', 'label' => 'ID'],
                ['field' => 'name', 'label' => 'Name'],
                ['field' => 'created_at', 'label' => 'Created At'],
            ];
        }

        $html = $this->open($node, 'section', 'ppd-data-grid');

        $html .= '<div class="ppd-grid-toolbar" data-ppd-part="toolbar">';
        $html .= '<div class="ppd-grid-toolbar-left">';
        if ($showAdd) {
            $html .= '<button class="ppd-btn ppd-btn-primary" data-ppd-part="add_button"><i class="bi bi-plus-lg"></i> Add New</button>';
        }
        foreach ($bulkActions as $action) {
            $label = $this->esc((string) ($action['label'] ?? $action['name'] ?? 'Bulk Action'));
            $id = $this->esc((string) ($action['id'] ?? strtolower(str_replace(' ', '_', $label))));
            $html .= '<button class="ppd-btn ppd-btn-light" data-ppd-part="bulk_action" data-ppd-part-id="' . $id . '">' . $label . '</button>';
        }
        $html .= '</div>';
        if ($showSearch) {
            $html .= '<div class="ppd-grid-toolbar-right" data-ppd-part="search"><input class="ppd-search" type="search" placeholder="Search..." /></div>';
        }
        $html .= '</div>';

        $html .= '<div class="ppd-table-wrap" data-ppd-part="table">';
        $html .= '<table class="ppd-table">';
        $html .= '<thead><tr>';
        $html .= '<th class="ppd-check"><input type="checkbox" /></th>';
        foreach ($columns as $index => $column) {
            $field = $this->esc((string) ($column['field'] ?? 'column_' . $index));
            $label = $this->esc((string) ($column['label'] ?? $column['name'] ?? $field));
            $html .= '<th data-ppd-part="column" data-ppd-field="' . $field . '">' . $label . '</th>';
        }
        if ($actions !== []) {
            $html .= '<th data-ppd-part="actions">Actions</th>';
        }
        $html .= '</tr></thead>';

        $html .= '<tbody>';
        for ($row = 1; $row <= 3; $row++) {
            $html .= '<tr data-ppd-part="sample_row">';
            $html .= '<td class="ppd-check"><input type="checkbox" /></td>';
            foreach ($columns as $index => $column) {
                $field = (string) ($column['field'] ?? 'column_' . $index);
                $html .= '<td data-ppd-part="cell" data-ppd-field="' . $this->esc($field) . '">' . $this->esc($this->sampleValue($field, $row)) . '</td>';
            }
            if ($actions !== []) {
                $html .= '<td class="ppd-actions">';
                foreach ($actions as $action) {
                    $label = (string) ($action['label'] ?? $action['name'] ?? 'Action');
                    $id = (string) ($action['id'] ?? strtolower(str_replace(' ', '_', $label)) . '_btn');
                    $icon = (string) ($action['icon'] ?? '');
                    $html .= '<button class="ppd-icon-btn" data-ppd-part="action_button" data-ppd-part-id="' . $this->esc($id) . '">'
                        . ($icon !== '' ? '<i class="' . $this->esc($icon) . '"></i> ' : '')
                        . $this->esc($label)
                        . '</button>';
                }
                $html .= '</td>';
            }
            $html .= '</tr>';
        }
        $html .= '</tbody></table></div>';

        $html .= '<div class="ppd-grid-footer" data-ppd-part="footer">';
        $html .= '<span>Showing 1 to 3 of 3 entries</span>';
        $html .= '<span class="ppd-pagination">‹ 1 ›</span>';
        $html .= '</div>';

        return $html . '</section>';
    }

    private function pagination(DesignerRenderNode $node): string
    {
        return $this->open($node, 'div', 'ppd-pagination') . '<button>‹</button><button class="active">1</button><button>›</button></div>';
    }

    private function section(DesignerRenderNode $node): string
    {
        $html = $this->open($node, 'section', 'ppd-section');
        foreach ($node->children() as $child) {
            if (is_array($child)) {
                $html .= $this->renderComponent($child);
            }
        }
        return $html . '</section>';
    }

    private function row(DesignerRenderNode $node): string
    {
        $html = $this->open($node, 'div', 'ppd-row');
        foreach ((array) ($node->props()['cells'] ?? []) as $cell) {
            $span = (int) ($cell['span'] ?? 12);
            $html .= '<div class="ppd-col ppd-col-' . max(1, min(12, $span)) . '" data-ppd-part="cell" data-ppd-part-id="' . $this->esc((string) ($cell['id'] ?? 'cell')) . '">';
            foreach ((array) ($cell['components'] ?? []) as $child) {
                if (is_array($child)) {
                    $html .= $this->renderComponent($child);
                }
            }
            $html .= '</div>';
        }
        return $html . '</div>';
    }

    private function generic(DesignerRenderNode $node): string
    {
        return $this->open($node, 'div', 'ppd-component ppd-component-' . $this->esc($node->type()))
            . '<span class="ppd-component-label">' . $this->esc($node->label()) . '</span>'
            . '</div>';
    }

    private function open(DesignerRenderNode $node, string $tag, string $class): string
    {
        return '<' . $tag
            . ' class="' . $class . '"'
            . ' data-ppd-component-id="' . $this->esc($node->id()) . '"'
            . ' data-ppd-component-type="' . $this->esc($node->type()) . '"'
            . '>';
    }

    private function sampleValue(string $field, int $row): string
    {
        return match ($field) {
            'id' => (string) $row,
            'name' => 'Sample Name ' . $row,
            'created_at' => date('Y-m-d'),
            default => ucwords(str_replace('_', ' ', $field)) . ' ' . $row,
        };
    }

    private function esc(string $value): string
    {
        return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
    }
}
