<?php

namespace XZD\AI\V5\Tools;

use XZD\AI\V5\AI\ImageClient;
use XZD\AI\V5\Core\Logger;

/**
 * AI定时写文章服务 — 插图插入 + 安全机制
 *
 * 负责在 AI 生成的文章中智能插入插图、追踪每日写作限额、
 * 确保内容质量和并发安全。
 */
class ScheduleWriteService
{
    /**
     * 在 Gutenberg 块数组中智能插入插图
     *
     * @param int    $postId            文章ID（用于媒体库关联）
     * @param array  $blocks            Gutenberg 块数组
     * @param int    $illustrationCount 需要插入的插图数量
     * @param string $imageSource       图片来源：ai / stock / public
     * @param string $articleTopic      文章主题（用于图片搜索上下文）
     * @return array [$blocks, $firstImageId] 更新后的块数组和第一张插图附件ID
     */
    public static function insertIllustrations(
        int $postId,
        array $blocks,
        int $illustrationCount,
        string $imageSource,
        string $articleTopic
    ): array {
        if ($illustrationCount <= 0 || $postId <= 0) {
            return [$blocks, 0];
        }

        $insertionPoints = self::findInsertionPoints($blocks, $illustrationCount);

        if (empty($insertionPoints)) {
            Logger::info('schedule_write', '未找到合适的插图位置，跳过插图插入');
            return [$blocks, 0];
        }

        $imageClient = ImageClient::instance();
        $firstImageId = 0;

        // 逆序处理插入点，保持索引正确
        for ($i = count($insertionPoints) - 1; $i >= 0; $i--) {
            $point = $insertionPoints[$i];
            $contextText = self::buildImageContext($blocks, $point['index'], $articleTopic);

            try {
                $result = $imageClient->generateInlineImage(
                    $postId,
                    $contextText,
                    $imageSource
                );

                if (empty($result['success'])) {
                    Logger::warning('schedule_write', '插图生成失败: ' . ($result['message'] ?? 'unknown'));
                    continue;
                }

                $imageBlock = GutenbergBlockBuilder::image(
                    (int)($result['attachment_id'] ?? 0),
                    $result['url'] ?? '',
                    $contextText,
                    ''
                );

                // 在锚点块之后插入图片块
                $insertAt = $point['index'] + 1;
                array_splice($blocks, $insertAt, 0, [$imageBlock]);

                if ($firstImageId === 0) {
                    $firstImageId = (int)($result['attachment_id'] ?? 0);
                }

                Logger::info('schedule_write', "插图已插入位置 {$point['index']} (来源: {$result['source']})");
            } catch (\Throwable $e) {
                Logger::error('schedule_write', '插图插入异常: ' . $e->getMessage());
            }
        }

        return [$blocks, $firstImageId];
    }

    /**
     * 在块数组中寻找最佳插图插入位置
     *
     * 策略：优先在标题块后插入，其次在段落组中点插入
     * 跳过第一个块（文章主标题），插图之间至少间隔2个块
     *
     * @param array $blocks    Gutenberg 块数组
     * @param int   $maxPoints 最多返回多少个位置
     * @return array 插入点数组 [['index' => int, 'anchor' => string, 'text' => string], ...]
     */
    private static function findInsertionPoints(array $blocks, int $maxPoints): array
    {
        $points = [];
        $lastInsertAt = -3;

        // 策略1：标题后插入（跳过第一个块/主标题）
        foreach ($blocks as $i => $block) {
            if (count($points) >= $maxPoints) break;
            if ($i === 0) continue;

            $blockName = $block['blockName'] ?? '';
            if (preg_match('/heading|zibll_biaoti/', $blockName) && ($i - $lastInsertAt) >= 2) {
                $points[] = [
                    'index'  => $i,
                    'anchor' => 'heading',
                    'text'   => wp_strip_all_tags($block['innerHTML'] ?? ''),
                ];
                $lastInsertAt = $i;
            }
        }

        // 策略2：如果标题不够，均匀分布在段落中
        if (count($points) < $maxPoints) {
            $paragraphIndices = [];
            foreach ($blocks as $i => $block) {
                if ($i <= 1) continue;
                $blockName = $block['blockName'] ?? '';
                if (preg_match('/paragraph/', $blockName)) {
                    $paragraphIndices[] = $i;
                }
            }

            $needed = $maxPoints - count($points);
            if (count($paragraphIndices) > 0 && $needed > 0) {
                $step = max(1, (int)(count($paragraphIndices) / ($needed + 1)));
                for ($j = $step - 1; $j < count($paragraphIndices) && count($points) < $maxPoints; $j += $step) {
                    $idx = $paragraphIndices[$j];
                    if (($idx - $lastInsertAt) >= 2) {
                        $points[] = [
                            'index'  => $idx,
                            'anchor' => 'paragraph',
                            'text'   => wp_strip_all_tags($blocks[$idx]['innerHTML'] ?? ''),
                        ];
                        $lastInsertAt = $idx;
                    }
                }
            }
        }

        return $points;
    }

    /**
     * 从块上下文构建图片搜索关键词
     *
     * 查找最近的标题文本作为图片主题，拼接文章主题
     */
    private static function buildImageContext(array $blocks, int $index, string $topic): string
    {
        // 向前查找最近的标题
        $headingBefore = '';
        for ($j = $index; $j >= 0; $j--) {
            $bn = $blocks[$j]['blockName'] ?? '';
            if (preg_match('/heading|zibll_biaoti/', $bn)) {
                $headingBefore = wp_strip_all_tags($blocks[$j]['innerHTML'] ?? '');
                break;
            }
        }

        // 向后查找最近的标题
        $headingAfter = '';
        $count = count($blocks);
        for ($j = $index + 1; $j < $count; $j++) {
            $bn = $blocks[$j]['blockName'] ?? '';
            if (preg_match('/heading|zibll_biaoti/', $bn)) {
                $headingAfter = wp_strip_all_tags($blocks[$j]['innerHTML'] ?? '');
                break;
            }
        }

        // 组合：前标题 + 文章主题 + 后标题 + 段落首句
        $parts = array_filter([$headingBefore, $topic, $headingAfter]);
        $context = implode(' - ', $parts);

        $paraText = wp_strip_all_tags($blocks[$index]['innerHTML'] ?? '');
        if ($paraText && mb_strlen($paraText) > 20) {
            $context .= ' | ' . mb_substr($paraText, 0, 200);
        }

        return mb_substr($context, 0, 500);
    }

    /**
     * 获取今日AI生成文章数量
     *
     * 优先使用 Transient 缓存（1小时），缓存失效时查询数据库
     */
    public static function getTodayWrittenCount(): int
    {
        $today = date('Y-m-d');
        $cacheKey = "xzd_daily_written_{$today}";
        $cached = get_transient($cacheKey);
        if ($cached !== false) {
            return (int)$cached;
        }

        // V3.1.7: 使用 SQL COUNT 代替 get_posts(posts_per_page=-1)，避免全表扫描
        global $wpdb;
        $count = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*)
             FROM {$wpdb->posts} p
             INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = '_xzd_ai_written'
             WHERE p.post_type = 'post'
               AND p.post_status IN ('draft', 'publish', 'pending')
               AND p.post_date >= %s
               AND p.post_date <= %s",
            $today . ' 00:00:00',
            $today . ' 23:59:59'
        ));

        set_transient($cacheKey, $count, HOUR_IN_SECONDS);
        return $count;
    }

    /**
     * 递增今日AI文章计数（写入新文章后调用）
     */
    public static function incrementTodayCount(): void
    {
        $today = date('Y-m-d');
        $cacheKey = "xzd_daily_written_{$today}";
        $count = (int)get_transient($cacheKey);
        set_transient($cacheKey, $count + 1, DAY_IN_SECONDS);
    }
}
