<?php

namespace XZD\AI\V5\Tools;

use XZD\AI\V5\Core\Logger;
use XZD\AI\V5\Theme\AdapterRegistry;
use XZD\AI\V5\Theme\AdapterInterface;

/**
 * Gutenberg 块构建器 — 统一入口，全部走主题适配器
 *
 * 所有方法委托给当前主题适配器，不硬编码任何块名称或HTML结构。
 * 切换主题时只需更换适配器，此类无需改动。
 *
 * @see AdapterInterface::buildBlock()  — 各适配器的实际实现
 * @see AdapterInterface::getBlockMapping() — 抽象类型→具体块名映射
 */
class GutenbergBlockBuilder
{
    /** @var AdapterInterface|null 缓存当前适配器 */
    private static ?AdapterInterface $adapter = null;

    private static function adapter(): AdapterInterface
    {
        if (self::$adapter === null) {
            self::$adapter = AdapterRegistry::getCurrent();
        }
        return self::$adapter;
    }

    /**
     * 重置适配器缓存（主题切换后调用）
     */
    public static function resetAdapter(): void
    {
        self::$adapter = null;
    }

    // ============================================================
    //  抽象类型 → 适配器委托 (所有块类型统一入口)
    // ============================================================

    public static function paragraph(string $content, array $attrs = []): array
    {
        return self::adapter()->buildBlock('paragraph', ['content' => $content, 'attrs' => $attrs]);
    }

    public static function heading(string $content, int $level = 2, ?string $anchor = null): array
    {
        return self::adapter()->buildBlock('heading', compact('content', 'level', 'anchor'));
    }

    public static function styledHeading(string $content, string $color = '#1fbc45', string $tag = 'h2'): array
    {
        return self::adapter()->buildBlock('styled_heading', compact('content', 'color', 'tag'));
    }

    public static function listBlock(array $items, bool $ordered = false): array
    {
        return self::adapter()->buildBlock('list', compact('items', 'ordered'));
    }

    public static function quote(string $content, string $citation = ''): array
    {
        return self::adapter()->buildBlock('quote', compact('content', 'citation'));
    }

    public static function styledQuote(string $content, string $color = ''): array
    {
        return self::adapter()->buildBlock('styled_quote', compact('content', 'color'));
    }

    public static function codeHighlight(string $code, string $language = 'generic', string $title = '', bool $linenumbers = true): array
    {
        return self::adapter()->buildBlock('code_highlight', compact('code', 'language', 'title', 'linenumbers'));
    }

    public static function code(string $code): array
    {
        return self::adapter()->buildBlock('code', ['code' => $code]);
    }

    public static function image(int $attachmentId, string $url, string $alt = '', string $caption = '', array $imgAttrs = []): array
    {
        return self::adapter()->buildBlock('image', [
            'id'      => $attachmentId,
            'url'     => $url,
            'alt'     => $alt,
            'caption' => $caption,
            'align'   => $imgAttrs['align'] ?? '',
        ]);
    }

    public static function alert(string $content, string $style = 'info', bool $closeable = false): array
    {
        return self::adapter()->buildBlock('alert', compact('content', 'style', 'closeable'));
    }

    public static function featureCard(string $title, string $note, string $icon = 'fa-star', string $color = ''): array
    {
        return self::adapter()->buildBlock('feature_card', compact('title', 'note', 'icon', 'color'));
    }

    public static function collapse(string $title, array $innerBlocks, bool $open = false): array
    {
        return self::adapter()->buildBlock('collapse', compact('title', 'innerBlocks', 'open'));
    }

    public static function buttonGroup(array $buttons, string $alignment = 'center'): array
    {
        return self::adapter()->buildBlock('button_group', compact('buttons', 'alignment'));
    }

    public static function postCard(int $postId): array
    {
        return self::adapter()->buildBlock('post_card', ['post_id' => $postId]);
    }

    public static function postList(string $type = 'related', int $limit = 5): array
    {
        return self::adapter()->buildBlock('post_list', compact('type', 'limit'));
    }

    public static function seamlessImg(array $innerBlocks): array
    {
        return self::adapter()->buildBlock('seamless_img', ['innerBlocks' => $innerBlocks]);
    }

    public static function table(array $headers, array $rows): array
    {
        return self::adapter()->buildBlock('table', compact('headers', 'rows'));
    }

    public static function separator(): array
    {
        return self::adapter()->buildBlock('separator', []);
    }

    public static function preformatted(string $content): array
    {
        return self::adapter()->buildBlock('preformatted', ['content' => $content]);
    }

    public static function pullquote(string $content, string $citation = ''): array
    {
        return self::adapter()->buildBlock('pullquote', compact('content', 'citation'));
    }

    public static function details(string $summary, array $innerBlocks): array
    {
        return self::adapter()->buildBlock('details', compact('summary', 'innerBlocks'));
    }

    public static function group(array $innerBlocks, array $attrs = []): array
    {
        // group 暂时不用适配器，直接构建
        $classes = 'wp-block-group';
        if (!empty($attrs['backgroundColor'])) {
            $classes .= ' has-' . $attrs['backgroundColor'] . '-background-color';
        }
        $innerHTML = '<div class="' . $classes . '">'
            . self::renderInnerBlocks($innerBlocks) . '</div>';
        return self::mkBlock('core/group',
            array_merge(['layout' => ['type' => 'constrained']], $attrs),
            $innerHTML, $innerBlocks);
    }

    public static function columns(array $columns): array
    {
        $innerBlocks = [];
        $innerHTML = "\n<div class=\"wp-block-columns\">\n";
        foreach ($columns as $col) {
            $childBlocks = $col['blocks'] ?? [];
            $width = $col['width'] ?? '';
            $colStyle = $width ? ' style="flex-basis:' . esc_attr($width) . '"' : '';
            $colInnerHTML = "\n<div class=\"wp-block-column\"" . $colStyle . ">\n"
                . self::renderInnerBlocks($childBlocks) . "</div>\n";
            $colBlock = self::mkBlock('core/column',
                $width ? ['width' => $width] : [],
                $colInnerHTML, $childBlocks);
            $innerBlocks[] = $colBlock;
            $innerHTML .= $colInnerHTML;
        }
        $innerHTML .= "</div>\n";
        return self::mkBlock('core/columns', [], $innerHTML, $innerBlocks);
    }

    // ============================================================
    //  AI结构化JSON → 块数组
    // ============================================================

    /**
     * AI返回结构化JSON → Gutenberg块数组
     *
     * AI块类型 → 抽象类型的映射:
     *   zibll_biaoti / styled_heading → styled_heading
     *   zibll_enlighter / code → code_highlight
     *   zibll_quote → styled_quote
     *   zibll_alert → alert
     *   zibll_feature → feature_card
     *   zibll_collapse → collapse
     *   zibll_buttons → button_group
     *   zibll_postsbox → post_card
     *   zibll_postslist → post_list
     *   zibll_seamlessimg → seamless_img
     */
    public static function fromStructuredJSON(array $aiBlocks): array
    {
        $blocks = [];
        $typeMap = [
            'zibll_biaoti'    => 'styled_heading',
            'zibll_enlighter'  => 'code_highlight',
            'zibll_quote'      => 'styled_quote',
            'zibll_alert'      => 'alert',
            'zibll_feature'    => 'feature_card',
            'zibll_collapse'   => 'collapse',
            'zibll_buttons'    => 'button_group',
            'zibll_postsbox'   => 'post_card',
            'zibll_postslist'  => 'post_list',
            'zibll_seamlessimg' => 'seamless_img',
            'zibll_enlighter'  => 'code_highlight',
            // 核心类型保持不变
        ];

        foreach ($aiBlocks as $item) {
            // V3.1.7 防御：AI可能返回非数组项（纯字符串等），自动转为段落块
            if (!is_array($item)) {
                $text = is_string($item) ? $item : json_encode($item, JSON_UNESCAPED_UNICODE);
                if (!empty(trim($text))) {
                    $blocks[] = self::paragraph($text);
                    Logger::info('GutenbergBlockBuilder', '字符串块转为段落: ' . mb_substr($text, 0, 80));
                }
                continue;
            }
            $rawType = $item['type'] ?? 'paragraph';
            $type = $typeMap[$rawType] ?? $rawType;
            $block = self::buildFromAI($type, $item);
            if ($block) $blocks[] = $block;
        }
        return $blocks;
    }

    private static function buildFromAI(string $type, array $item): ?array
    {
        $adapter = self::adapter();

        switch ($type) {
            case 'paragraph':
                return self::paragraph($item['content'] ?? '', $item['attrs'] ?? []);

            case 'heading':
                return self::heading($item['content'] ?? '', $item['level'] ?? 2, $item['anchor'] ?? null);

            case 'styled_heading':
                return self::styledHeading($item['content'] ?? '',
                    $item['color'] ?? '#1fbc45',
                    $item['tag'] ?? 'h2');

            case 'list':
                $items = $item['items'] ?? [];
                if (!empty($items) && is_string($items[0] ?? null)) {
                    $items = array_map(fn($s) => ['content' => $s], $items);
                }
                return self::listBlock($items, $item['ordered'] ?? false);

            case 'quote':
                return self::quote($item['content'] ?? '', $item['citation'] ?? '');

            case 'styled_quote':
                return self::styledQuote($item['content'] ?? '', $item['color'] ?? '');

            case 'code':
                return self::code($item['code'] ?? $item['content'] ?? '');

            case 'code_highlight':
                return self::codeHighlight(
                    $item['code'] ?? $item['content'] ?? '',
                    $item['language'] ?? 'generic',
                    $item['title'] ?? '',
                    $item['linenumbers'] ?? true
                );

            case 'image':
                return self::image((int) ($item['id'] ?? 0), $item['url'] ?? '',
                    $item['alt'] ?? '', $item['caption'] ?? '', $item);

            case 'alert':
                return self::alert($item['content'] ?? '',
                    $item['style'] ?? 'info',
                    $item['closeable'] ?? false);

            case 'feature_card':
                return self::featureCard($item['title'] ?? '', $item['note'] ?? '',
                    $item['icon'] ?? 'fa-star', $item['color'] ?? '');

            case 'collapse':
                $inner = $item['content'] ?? [];
                if (is_string($inner)) {
                    $inner = [self::paragraph($inner)];
                } elseif (isset($inner['type'])) {
                    $inner = [self::buildFromAI($inner['type'], $inner)];
                } else {
                    $inner = self::fromStructuredJSON($inner);
                }
                return self::collapse($item['title'] ?? '展开查看', $inner, $item['open'] ?? false);

            case 'button_group':
                return self::buttonGroup($item['buttons'] ?? [], $item['alignment'] ?? 'center');

            case 'post_card':
                return self::postCard((int) ($item['post_id'] ?? 0));

            case 'post_list':
                return self::postList($item['type'] ?? 'related', (int) ($item['limit'] ?? 5));

            case 'table':
                return self::table($item['headers'] ?? [], $item['rows'] ?? []);

            case 'separator':
                return self::separator();

            case 'preformatted':
                return self::preformatted($item['content'] ?? '');

            case 'pullquote':
                return self::pullquote($item['content'] ?? '', $item['citation'] ?? '');

            case 'details':
                return self::details($item['summary'] ?? '详情',
                    self::fromStructuredJSON($item['blocks'] ?? []));

            case 'columns':
                $cols = $item['columns'] ?? [];
                foreach ($cols as &$col) {
                    if (isset($col['blocks'])) {
                        $col['blocks'] = self::fromStructuredJSON($col['blocks']);
                    }
                }
                return self::columns($cols);

            case 'group':
                return self::group(self::fromStructuredJSON($item['blocks'] ?? []), $item['attrs'] ?? []);

            default:
                if (!empty($item['content'])) return self::paragraph($item['content']);
                return null;
        }
    }

    // ============================================================
    //  序列化 + 块解析
    // ============================================================

    /**
     * 块数组 → post_content 字符串
     */
    public static function serialize(array $blocks): string
    {
        if (function_exists('serialize_blocks')) {
            return serialize_blocks($blocks);
        }
        // 降级
        $content = '';
        foreach ($blocks as $block) {
            $name = $block['blockName'] ?? 'core/paragraph';
            $attrs = !empty($block['attrs'])
                ? ' ' . json_encode($block['attrs'], JSON_UNESCAPED_UNICODE | JSON_HEX_TAG)
                : '';
            $content .= '<!-- wp:' . $name . $attrs . ' -->' . "\n"
                . ($block['innerHTML'] ?? '') . "\n"
                . '<!-- /wp:' . $name . ' -->' . "\n\n";
        }
        return trim($content);
    }

    /**
     * 获取适配器（供外部在需要时直接调用适配器方法）
     */
    public static function getBlockMapping(): array
    {
        return self::adapter()->getBlockMapping();
    }

    public static function getTextBlockNames(): array
    {
        return self::adapter()->getTextBlockNames();
    }

    public static function getAIBlockGuidelines(): string
    {
        return self::adapter()->getAIBlockGuidelines();
    }

    // ============================================================
    //  内部辅助
    // ============================================================

    private static function mkBlock(string $name, array $attrs, string $innerHTML, array $children = []): array
    {
        return [
            'blockName'    => $name,
            'attrs'        => $attrs,
            'innerBlocks'  => $children,
            'innerHTML'    => $innerHTML,
            'innerContent' => [$innerHTML],
        ];
    }

    private static function renderInnerBlocks(array $blocks): string
    {
        $html = '';
        foreach ($blocks as $b) $html .= ($b['innerHTML'] ?? '') . "\n";
        return $html;
    }
}
