<?php

namespace HaoZiTeam\AIPost\Service\Settings\Traits;

use HaoZiTeam\AIPost\Service\Features\Logger;

defined('ABSPATH') || exit;

trait TraitTasksRouteAndValidate
{
    // 读取端合并：当任何代码 get_option('ai-post') 时，把独立存储的任务合并回 $opts['tasks']。
    public function merge_tasks_into_ai_post($opts)
    {
        try {
            if (!is_array($opts)) { $opts = []; }
            $tasks = \get_option('ai-post-tasks', []);
            if (is_array($tasks) && !empty($tasks)) {
                $opts['tasks'] = $tasks;
            }
            return $opts;
        } catch (\Throwable $e) {
            Logger::warning('MergeTasks: view error: ' . $e->getMessage(), 'Setting');
            return $opts;
        }
    }

    // 校验：CGPS AJAX 保存时对文章步骤进行预检（不通过返回错误提示，通过返回 false 继续保存）
    public function validate_steps_on_ajax_save($result)
    {
        try {
            if (!isset($_POST['data'])) { return false; }
            $payload = json_decode(stripslashes((string)$_POST['data']), true);
            if (!is_array($payload)) { return false; }

            // 解析两种结构
            $tasks_list = [];
            if (isset($payload['ai-post-tasks']) && is_array($payload['ai-post-tasks'])) {
                $tasks_list = $payload['ai-post-tasks'];
            } elseif (isset($payload['ai-post']) && is_array($payload['ai-post']) && isset($payload['ai-post']['tasks']) && is_array($payload['ai-post']['tasks'])) {
                $tasks_list = $payload['ai-post']['tasks'];
            } else {
                return false; // 无任务数据，不处理
            }

            $invalid = [];
            foreach ($tasks_list as $idx => $task) {
                if (empty($task['post-steps']) || !is_array($task['post-steps'])) { continue; }
                $last = end($task['post-steps']);
                $receive = isset($last['receive']) ? (bool)$last['receive'] : false;
                $rtype   = isset($last['receive-type']) ? (string)$last['receive-type'] : '';
                if (!($receive && $rtype === 'content')) {
                    $invalid[] = (string)$idx;
                }
            }

            if (!empty($invalid)) {
                $msg = '以下任务的文章步骤不满足要求（最后一步必须为“主体”且“接收回复”）：' . implode(', ', $invalid);
                return ['code' => 500, 'msg' => $msg];
            }
        } catch (\Throwable $e) {
            // 不中断保存，记录以便排查
            Logger::warning('AJAX Steps Validate Error: ' . $e->getMessage(), 'Setting');
            return false;
        }
        return false; // 返回 false 代表通过，让框架继续保存
    }

    // 校验：每个任务的文章步骤最后一项必须“接收回复=true 且 接收回复作为=主体(content)”
    // 若不满足：阻止保存（返回旧值），并设置一次性提示。
    public function validate_steps_before_save($new_value, $old_value, $option)
    {
        try {
            if (!is_array($new_value)) { return $new_value; }

            // 统一“任务列表”视图
            $tasks_list = [];
            if ($option === 'ai-post-tasks') {
                // 形如 [0=>task,1=>task,...]
                $tasks_list = $new_value;
            } else {
                // 形如 ['tasks'=>[...], ...]
                if (empty($new_value['tasks']) || !is_array($new_value['tasks'])) { return $new_value; }
                $tasks_list = $new_value['tasks'];
            }

            $invalid = [];
            foreach ($tasks_list as $idx => $task) {
                if (empty($task['post-steps']) || !is_array($task['post-steps'])) { continue; }
                $last = end($task['post-steps']);
                // receive-type 只有在 receive=true 时才出现（有 dependency），因此需要两者同时校验
                $receive = isset($last['receive']) ? (bool)$last['receive'] : false;
                $rtype   = isset($last['receive-type']) ? (string)$last['receive-type'] : '';
                if (!($receive && $rtype === 'content')) {
                    $invalid[] = (string)$idx;
                }
            }

            if (!empty($invalid)) {
                // 写入一次性提示并阻止保存
                if (function_exists('set_transient')) {
                    set_transient('aipost_steps_validation_error', '以下任务的文章步骤不满足要求（最后一步必须为“主体”且“接收回复”）：' . implode(', ', $invalid), 60);
                } else {
                    update_option('aipost_steps_validation_error', '以下任务的文章步骤不满足要求（最后一步必须为“主体”且“接收回复”）：' . implode(', ', $invalid));
                }
                return $old_value; // 阻止保存（无论是 ai-post 还是 ai-post-tasks）
            }
        } catch (\Throwable $e) {
            // 出现异常不阻断保存，但记录日志以便排查
            Logger::warning('Validate Steps Error: ' . $e->getMessage(), 'Setting');
            return $new_value;
        }
        return $new_value;
    }

    // 在后台顶部输出一次性提示
    public function maybe_show_steps_validation_notice(): void
    {
        $msg = false;
        if (function_exists('get_transient')) {
            $msg = get_transient('aipost_steps_validation_error');
            if ($msg) { delete_transient('aipost_steps_validation_error'); }
        } else {
            $msg = get_option('aipost_steps_validation_error');
            if ($msg) { delete_option('aipost_steps_validation_error'); }
        }
        if ($msg) {
            echo '<div class="notice notice-error is-dismissible"><p>' . esc_html($msg) . '</p><p>请确保：<strong>最后一个步骤</strong>设置为“接收回复=开启”，且“接收回复作为=主体”。否则会导致只生成标题而不落地正文，产生令牌浪费且文章发布失败。</p></div>';
        }
    }

    // 页脚注入：AJAX 保存失败后，移除灰层并展示友好提示，避免界面卡住
    public function inject_ajax_fail_recovery_js(): void
    {
        ?>
        <script>
        (function($){
            // 记录按钮原始文字，便于从“正在保存”恢复
            $(function(){
                $('.cgps-save').each(function(){
                    var $b = $(this);
                    if (!$b.data('label')) { $b.data('label', $b.attr('value') || $b.text() || '保存配置'); }
                });
            });

            function restoreSaveButtons(){
                $('.cgps-options').removeClass('cgps-saving');
                $('.cgps-save').each(function(){
                    var $b = $(this);
                    var orig = $b.data('label') || '保存配置';
                    $b.prop('disabled', false).attr('value', orig).text(orig);
                });
                // 重新绑定 cgps 的保存处理，避免因失败导致内部状态锁死
                try {
                    if ($.fn && $.fn.cgps_save) {
                        $('.cgps-save').off('click');
                        $('.cgps-save').cgps_save();
                    }
                } catch(e){}
            }

            function showNotice(msg){
                var $wrap = $('.wrap:first');
                if(!$wrap.length){ $wrap = $('#wpbody-content'); }
                var $n = $('<div class="notice notice-error is-dismissible"><p></p></div>');
                $n.find('p').text(msg || '保存失败');
                $wrap.prepend($n);
            }
            // 监听 AJAX 错误（含 cgps_*_ajax_save）
            $(document).ajaxError(function(event, jqxhr, settings){
                try{
                    if (settings && settings.url && settings.url.indexOf('_ajax_save') !== -1) {
                        cleanup();
                        var msg = (jqxhr.responseJSON && jqxhr.responseJSON.error) ? jqxhr.responseJSON.error : '保存失败';
                        showNotice(msg);
                    }
                }catch(e){}
            });
            // 无论成功失败，只要保存请求完成，均尝试移除灰层，防止残留
            $(document).ajaxComplete(function(event, jqxhr, settings){
                try{
                    if (settings && settings.url && settings.url.indexOf('_ajax_save') !== -1) {
                        cleanup();
                    }
                }catch(e){}
            });
            // 覆盖 alert：若出现错误弹窗，自动恢复按钮
            var __origAlert = window.alert;
            window.alert = function(msg){
                try{
                    if (typeof msg === 'string' && /错误|失败|error/i.test(msg)){
                        restoreSaveButtons();
                        showNotice(msg);
                        return;
                    }
                }catch(e){}
                if (typeof __origAlert === 'function') { __origAlert(msg); }
            };
            
            // 针对 CGPS 的 AJAX 保存：在完成后检查响应结果，若包含“步骤不满足要求”，恢复保存按钮
            $(document).ajaxComplete(function(event, xhr, settings){
                try{
                    // 任意 AJAX 完成后，清理可能的“保存超时”守护
                    if (window.__aipostSavingGuard) {
                        clearTimeout(window.__aipostSavingGuard); window.__aipostSavingGuard = null;
                    }
                    var rt = xhr && xhr.responseText ? String(xhr.responseText) : '';
                    // 后端直接返回 HTML（如 404/拦截页）或配置校验提示时，均恢复按钮
                    var looksLikeHTML = /<html[\s\S]*<\/html>/i.test(rt) || /<title>.*<\/title>/i.test(rt);
                    if (xhr && (xhr.status >= 400 || rt.indexOf('以下任务的文章步骤不满足要求') !== -1 || looksLikeHTML)){
                        restoreSaveButtons();
                    }
                }catch(e){}
            });

            // 点击保存后设置兜底超时：若出现错误提示，则解除“正在保存”状态，允许二次保存
            $(document).on('click', '.cgps-save', function(){
                // 启动“保存超时”守护：12秒未结束则自动恢复
                try {
                    if (window.__aipostSavingGuard) { clearTimeout(window.__aipostSavingGuard); }
                    window.__aipostSavingGuard = setTimeout(function(){
                        if ($('.cgps-options').hasClass('cgps-saving')){
                            restoreSaveButtons();
                            showNotice('[AI-Post] 保存超时或被拦截，请重试。如反复失败，请检查 WAF/CDN 对后台 AJAX 的放行。');
                        }
                        window.__aipostSavingGuard = null;
                    }, 12000);
                }catch(e){}
                setTimeout(function(){
                    try{
                        var hasError = $('.notice-error:contains("以下任务的文章步骤不满足要求")').length > 0;
                        if (hasError) { restoreSaveButtons(); }
                    }catch(e){}
                }, 1500);
            });

            // 监听全局 Notice 注入，出现任何 .notice-error 都恢复按钮
            var target = document.querySelector('#wpbody-content') || document.body;
            if (target && window.MutationObserver){
                var mo = new MutationObserver(function(muts){
                    try{
                        if (jQuery('.notice-error').length){ restoreSaveButtons(); }
                    }catch(e){}
                });
                mo.observe(target, { childList: true, subtree: true });
            }

            // 兜底轮询：若无进行中的 AJAX 且仍残留灰层，则移除
            setInterval(function(){
                try{
                    if (window.jQuery && jQuery.active === 0 && $('.cgps-options').hasClass('cgps-saving')){
                        restoreSaveButtons();
                    }
                }catch(e){}
            }, 2000);
        })(jQuery);
        </script>
        <?php
    }

    // 保存路由：当保存 ai-post 时，如包含 tasks 字段，则路由到独立选项 ai-post-tasks 并移除原 tasks
    public function route_tasks_on_save($new_value, $old_value, $option)
    {
        try {
            if ($option !== 'ai-post') { return $new_value; }
            if (!is_array($new_value)) { return $new_value; }
            if (empty($new_value['tasks']) || !is_array($new_value['tasks'])) { return $new_value; }

            $tasks = $new_value['tasks'];

            // 先执行一次完整校验（借用已有的校验函数，保证与直接保存 ai-post-tasks 的一致性）
            $valid = $this->validate_steps_before_save($tasks, $tasks, 'ai-post-tasks');
            if ($valid !== $tasks) {
                // 校验失败：保持 new_value 不变，让上游逻辑处理提示
                return $new_value;
            }

            // 将任务写入独立选项
            update_option('ai-post-tasks', $tasks);

            // 从 ai-post 中移除 tasks，避免双处存储引发不一致
            unset($new_value['tasks']);

            return $new_value;
        } catch (\Throwable $e) {
            Logger::warning('Route Tasks Error: ' . $e->getMessage(), 'Setting');
            return $new_value;
        }
    }

    // 只读日志回显：保存 ai-post-tasks 时打印与文生图相关关键字段，不更改入库值
    public function log_task_flags_on_save($new_value, $old_value, $option)
    {
        try {
            if ($option !== 'ai-post-tasks') { return $new_value; }
            if (!is_array($new_value)) { return $new_value; }

            // 避免刷屏：最多回显前 10 个任务的关键字段
            $max = 10;
            $idx = 0;
            foreach ($new_value as $k => $task) {
                if ($idx++ >= $max) { break; }
                if (!is_array($task)) { continue; }

                $enable   = isset($task['enable-doubao-imagegen']) ? (bool)$task['enable-doubao-imagegen'] : false;
                $provider = isset($task['imagegen-provider']) ? (string)$task['imagegen-provider'] : '';

                // 阿里云（任务覆盖）
                $ali_model   = isset($task['aliyun-imagegen-model-task']) ? (string)$task['aliyun-imagegen-model-task'] : '';
                $ali_aspect1 = isset($task['aliyun-imagegen-aspect-qwen-task']) ? (string)$task['aliyun-imagegen-aspect-qwen-task'] : '';
                $ali_aspect2 = isset($task['aliyun-imagegen-aspect-wan-task']) ? (string)$task['aliyun-imagegen-aspect-wan-task'] : '';
                $ali_n       = isset($task['aliyun-imagegen-n-task']) ? (int)$task['aliyun-imagegen-n-task'] : 0;

                // 豆包（任务覆盖）
                $db_size   = isset($task['doubao-imagegen-size-task']) ? (string)$task['doubao-imagegen-size-task'] : '';
                $db_count  = isset($task['doubao-imagegen-image-count']) ? (int)$task['doubao-imagegen-image-count'] : 0;

                // 通用
                $dl_media = isset($task['doubao-imagegen-download-to-media']) ? (bool)$task['doubao-imagegen-download-to-media'] : null;

                // 统一构造摘要
                $parts = [];
                $parts[] = 'enable=' . ($enable ? 'ON' : 'OFF');
                $parts[] = 'provider=' . ($provider !== '' ? $provider : '');
                if ($provider === 'aliyun') {
                    $parts[] = 'ali.model=' . $ali_model;
                    $parts[] = 'ali.aspect.qwen=' . $ali_aspect1;
                    $parts[] = 'ali.aspect.wan=' . $ali_aspect2;
                    $parts[] = 'ali.n=' . $ali_n;
                } elseif ($provider === 'doubao' || $provider === '') { // 兼容默认 provider
                    $parts[] = 'db.size=' . $db_size;
                    $parts[] = 'db.count=' . $db_count;
                }
                if ($dl_media !== null) {
                    $parts[] = 'download_to_media=' . ($dl_media ? 'ON' : 'OFF');
                }

                // 输出日志（不含任何敏感令牌，仅配置位与枚举值）
                Logger::debug('SaveTasks: task_key=' . (string)$k . ' | ' . implode(' | ', $parts), 'Setting');
            }
        } catch (\Throwable $e) {
            // 不阻断保存，仅记录异常
            Logger::warning('SaveTasks: exception: ' . $e->getMessage(), 'Setting');
        }
        return $new_value;
    }
}
