<?php
/**
 * Plugin Name: 微信公众号文章采集器
 * Plugin URI: https://www.rifengwf.com
 * Description: 自动采集微信公众号文章并发布到WordPress指定栏目，支持去重、定时采集。
 * Version: 1.0.0
 * Author: Rifeng Weifang
 * Text Domain: wechat-collector
 */

if (!defined('ABSPATH')) exit;

define('WAC_VERSION', '1.0.0');
define('WAC_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WAC_PLUGIN_URL', plugin_dir_url(__FILE__));

/**
 * 主插件类
 */
class WeChat_Article_Collector {

    private static $instance = null;
    private $option_name = 'wechat_collector_options';

    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        // 激活时创建数据表和定时任务
        register_activation_hook(__FILE__, array($this, 'activate'));
        // 停用时清除定时任务
        register_deactivation_hook(__FILE__, array($this, 'deactivate'));

        // 后台菜单
        add_action('admin_menu', array($this, 'add_admin_menu'));
        // 注册设置
        add_action('admin_init', array($this, 'register_settings'));

        // 定时任务
        add_filter('cron_schedules', array($this, 'add_cron_intervals'));
        add_action('wechat_collector_cron_hook', array($this, 'run_collection'));

        // AJAX处理
        add_action('wp_ajax_wac_manual_collect', array($this, 'ajax_manual_collect'));
        add_action('wp_ajax_wac_collect_single_url', array($this, 'ajax_collect_single_url'));
        add_action('wp_ajax_wac_get_logs', array($this, 'ajax_get_logs'));
        add_action('wp_ajax_wac_clear_logs', array($this, 'ajax_clear_logs'));

        // 加载JS/CSS
        add_action('admin_enqueue_scripts', array($this, 'admin_scripts'));
    }

    /**
     * 插件激活
     */
    public function activate() {
        global $wpdb;

        // 创建采集记录表
        $table_name = $wpdb->prefix . 'wechat_collected';
        $charset_collate = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE IF NOT EXISTS $table_name (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            article_url varchar(500) NOT NULL,
            article_title varchar(300) DEFAULT '',
            article_hash varchar(32) NOT NULL,
            post_id bigint(20) DEFAULT 0,
            collected_at datetime DEFAULT CURRENT_TIMESTAMP,
            status varchar(20) DEFAULT 'success',
            PRIMARY KEY (id),
            UNIQUE KEY article_hash (article_hash),
            KEY article_url (article_url(191))
        ) $charset_collate;";

        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql);

        // 设置默认选项
        $defaults = array(
            'account_name'    => '日丰管',
            'target_category' => '',
            'target_page_id'  => 0,
            'collect_method'  => 'manual_urls',
            'rss_url'         => '',
            'manual_urls'     => '',
            'schedule'        => 'daily',
            'max_articles'    => 10,
            'auto_publish'    => 1,
            'post_status'     => 'publish',
            'last_run'        => '',
            'last_result'     => '',
        );

        $existing = get_option($this->option_name);
        if (!is_array($existing)) {
            $existing = array();
        }
        update_option($this->option_name, array_merge($defaults, $existing));

        // 设置定时任务
        if (!wp_next_scheduled('wechat_collector_cron_hook')) {
            wp_schedule_event(time(), 'daily', 'wechat_collector_cron_hook');
        }

        $this->log('插件已激活，定时任务已设置');
    }

    /**
     * 插件停用
     */
    public function deactivate() {
        wp_clear_scheduled_hook('wechat_collector_cron_hook');
        $this->log('插件已停用，定时任务已清除');
    }

    /**
     * 添加自定义Cron间隔
     */
    public function add_cron_intervals($schedules) {
        $schedules['every_six_hours'] = array(
            'interval' => 21600,
            'display'  => '每6小时一次'
        );
        $schedules['every_twelve_hours'] = array(
            'interval' => 43200,
            'display'  => '每12小时一次'
        );
        return $schedules;
    }

    /**
     * 添加后台菜单
     */
    public function add_admin_menu() {
        add_menu_page(
            '微信文章采集',
            '微信文章采集',
            'manage_options',
            'wechat-collector',
            array($this, 'render_admin_page'),
            'dashicons-rss',
            30
        );
    }

    /**
     * 注册设置
     */
    public function register_settings() {
        register_setting('wechat_collector_settings', $this->option_name);
    }

    /**
     * 加载后台脚本
     */
    public function admin_scripts($hook) {
        if (strpos($hook, 'wechat-collector') === false) return;

        wp_enqueue_style('wac-admin-css', WAC_PLUGIN_URL . 'admin.css', array(), WAC_VERSION);
        wp_enqueue_script('wac-admin-js', WAC_PLUGIN_URL . 'admin.js', array('jquery'), WAC_VERSION, true);
        wp_localize_script('wac-admin-js', 'wac_ajax', array(
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce'    => wp_create_nonce('wac_ajax_nonce'),
        ));
    }

    // ==========================================
    //  采集核心逻辑
    // ==========================================

    /**
     * 执行采集任务
     */
    public function run_collection() {
        $options = get_option($this->option_name);
        $method = isset($options['collect_method']) ? $options['collect_method'] : 'sogou';
        $max = isset($options['max_articles']) ? intval($options['max_articles']) : 10;

        $this->log("========== 开始采集任务 ==========");
        $this->log("采集方式: {$method}, 最大数量: {$max}");

        $articles = array();

        switch ($method) {
            case 'sogou':
                $articles = $this->collect_from_sogou($options);
                break;
            case 'rss':
                $articles = $this->collect_from_rss($options);
                break;
            case 'manual_urls':
                $articles = $this->collect_from_manual_urls($options);
                break;
        }

        if (empty($articles)) {
            $this->log('未发现新文章');
            update_option($this->option_name, array_merge($options, array(
                'last_run'    => current_time('mysql'),
                'last_result' => '未发现新文章',
            )));
            return;
        }

        $this->log("发现 " . count($articles) . " 篇文章，开始处理...");

        $collected = 0;
        $skipped = 0;

        foreach (array_slice($articles, 0, $max) as $article) {
            // 检查是否已采集
            if ($this->is_collected($article['url'])) {
                $this->log("跳过已采集: " . mb_substr($article['title'], 0, 30));
                $skipped++;
                continue;
            }

            // 采集文章详情
            $content = $this->fetch_article_content($article['url']);
            if (!$content) {
                $this->log("采集内容失败: " . $article['url']);
                continue;
            }

            // 创建WordPress文章
            $post_id = $this->create_post($article, $content, $options);
            if ($post_id) {
                // 记录已采集
                $this->record_collected($article['url'], $article['title'], $post_id);
                $collected++;
                $this->log("✓ 已发布: " . mb_substr($article['title'], 0, 30) . " (ID: {$post_id})");
            } else {
                $this->log("✗ 发布失败: " . mb_substr($article['title'], 0, 30));
            }

            // 避免请求过快
            sleep(rand(2, 5));
        }

        $result = "采集完成: 新发布 {$collected} 篇, 跳过 {$skipped} 篇";
        $this->log($result);
        $this->log("========== 采集任务结束 ==========\n");

        update_option($this->option_name, array_merge($options, array(
            'last_run'    => current_time('mysql'),
            'last_result' => $result,
        )));
    }

    /**
     * 方法1: 通过搜狗微信搜索采集
     */
    private function collect_from_sogou($options) {
        $account_name = urlencode($options['account_name']);
        $url = "https://weixin.sogou.com/weixin?type=2&query={$account_name}&ie=utf8&_sug_=n&_sug_type_=";

        $this->log("搜狗搜索: {$url}");

        $response = wp_remote_get($url, array(
            'timeout'    => 30,
            'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            'headers'    => array(
                'Accept'          => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'Accept-Language' => 'zh-CN,zh;q=0.9,en;q=0.8',
                'Referer'         => 'https://weixin.sogou.com/',
            ),
        ));

        if (is_wp_error($response)) {
            $this->log("搜狗请求失败: " . $response->get_error_message());
            return array();
        }

        $body = wp_remote_retrieve_body($response);
        if (empty($body)) {
            $this->log("搜狗返回内容为空");
            return array();
        }

        return $this->parse_sogou_results($body);
    }

    /**
     * 解析搜狗搜索结果
     */
    private function parse_sogou_results($html) {
        $articles = array();

        // 方法1: 提取所有包含微信文章链接的<a>标签
        if (preg_match_all('/<a[^>]*href="([^"]*(?:\/link\?|mp\.weixin\.qq\.com)[^"]*)"[^>]*>(.*?)<\/a>/si', $html, $matches, PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                $url = html_entity_decode($match[1]);
                $title = wp_strip_all_tags($match[2]);
                $title = trim(html_entity_decode($title, ENT_QUOTES, 'UTF-8'));

                // 跳过空标题或太短的标题
                if (mb_strlen($title) < 5) continue;

                // 处理搜狗跳转链接
                if (strpos($url, '/link?') !== false) {
                    // 补全为完整URL
                    if (strpos($url, 'http') !== 0) {
                        $url = 'https://weixin.sogou.com' . $url;
                    }
                    $real_url = $this->resolve_sogou_redirect($url);
                    if ($real_url && strpos($real_url, 'mp.weixin.qq.com') !== false) {
                        $url = $real_url;
                    } else {
                        continue; // 跳过无法解析的链接
                    }
                }

                // 验证是微信文章链接
                if (strpos($url, 'mp.weixin.qq.com') === false) continue;

                $articles[] = array('title' => $title, 'url' => $url);
            }
        }

        // 方法2: 从data-url属性中提取（搜狗新版页面）
        if (empty($articles) && preg_match_all('/data-url="([^"]*mp\.weixin\.qq\.com[^"]*)"/i', $html, $matches)) {
            foreach ($matches[1] as $i => $url) {
                $url = html_entity_decode($url);
                // 尝试从附近提取标题
                $title = '';
                $pos = strpos($html, $matches[0][$i]);
                if ($pos !== false) {
                    $context = substr($html, max(0, $pos - 200), 400);
                    if (preg_match('/>([^<]{5,100})</', $context, $tm)) {
                        $title = trim($tm[1]);
                    }
                }
                if (!empty($title)) {
                    $articles[] = array('title' => $title, 'url' => $url);
                }
            }
        }

        // 方法3: 从<script>中的文章数据提取（搜狗JSON数据）
        if (empty($articles) && preg_match('/var\s+articleList\s*=\s*(\[.*?\]);/s', $html, $m)) {
            $json_data = json_decode($m[1], true);
            if (is_array($json_data)) {
                foreach ($json_data as $item) {
                    if (!empty($item['url']) && !empty($item['title'])) {
                        $articles[] = array('title' => $item['title'], 'url' => $item['url']);
                    }
                }
            }
        }

        $this->log("搜狗解析到 " . count($articles) . " 篇文章");
        return $articles;
    }

    /**
     * 解析搜狗跳转链接
     */
    private function resolve_sogou_redirect($url) {
        // 确保是完整URL
        if (strpos($url, 'http') !== 0) {
            $url = 'https://weixin.sogou.com' . $url;
        }

        // 方法1: 通过HEAD请求获取跳转地址
        $response = wp_remote_head($url, array(
            'timeout'     => 15,
            'redirection' => 0,
            'user-agent'  => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            'headers'     => array(
                'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            ),
        ));

        if (!is_wp_error($response)) {
            $location = wp_remote_retrieve_header($response, 'location');
            if (!empty($location)) {
                // 处理相对路径
                if (strpos($location, '/') === 0) {
                    $location = 'https://weixin.sogou.com' . $location;
                }
                if (strpos($location, 'mp.weixin.qq.com') !== false) {
                    return html_entity_decode($location);
                }
            }
        }

        // 方法2: 通过GET请求从页面中提取真实URL
        $response = wp_remote_get($url, array(
            'timeout'    => 15,
            'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            'headers'    => array(
                'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            ),
        ));

        if (is_wp_error($response)) return null;

        $body = wp_remote_retrieve_body($response);

        // 提取JavaScript中的URL
        if (preg_match('/url\s*=\s*["\']([^"\']*mp\.weixin\.qq\.com[^"\']*)/i', $body, $m)) {
            return html_entity_decode($m[1]);
        }
        // 提取meta refresh中的URL
        if (preg_match('/content="0;url=([^"]*)"/i', $body, $m)) {
            $redirect_url = html_entity_decode($m[1]);
            if (strpos($redirect_url, 'http') !== 0) {
                $redirect_url = 'https://weixin.sogou.com' . $redirect_url;
            }
            return $redirect_url;
        }
        // 提取window.location
        if (preg_match('/window\.location\s*=\s*["\']([^"\']*mp\.weixin\.qq\.com[^"\']*)/i', $body, $m)) {
            return html_entity_decode($m[1]);
        }

        return null;
    }

    /**
     * 验证URL是否有效
     */
    private function is_valid_wechat_url($url) {
        if (empty($url)) return false;
        if (strpos($url, 'mp.weixin.qq.com') === false) return false;
        if (strpos($url, '/s/') === false && strpos($url, 'mp.weixin.qq.com/s?') === false) return false;
        return true;
    }

    /**
     * 方法2: 通过RSS采集
     */
    private function collect_from_rss($options) {
        $rss_url = isset($options['rss_url']) ? $options['rss_url'] : '';
        if (empty($rss_url)) {
            $this->log("RSS URL未配置");
            return array();
        }

        $this->log("RSS采集: {$rss_url}");

        $response = wp_remote_get($rss_url, array(
            'timeout'    => 30,
            'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        ));

        if (is_wp_error($response)) {
            $this->log("RSS请求失败: " . $response->get_error_message());
            return array();
        }

        $body = wp_remote_retrieve_body($response);
        return $this->parse_rss($body);
    }

    /**
     * 解析RSS内容
     */
    private function parse_rss($xml_content) {
        $articles = array();

        try {
            libxml_use_internal_errors(true);
            $xml = simplexml_load_string($xml_content);
            if (!$xml) {
                $this->log("RSS XML解析失败");
                return array();
            }

            // RSS 2.0
            if (isset($xml->channel->item)) {
                foreach ($xml->channel->item as $item) {
                    $articles[] = array(
                        'title' => (string)$item->title,
                        'url'   => (string)$item->link,
                    );
                }
            }
            // Atom
            elseif (isset($xml->entry)) {
                foreach ($xml->entry as $entry) {
                    $link = '';
                    if (isset($entry->link['href'])) {
                        $link = (string)$entry->link['href'];
                    } elseif (isset($entry->link)) {
                        $link = (string)$entry->link;
                    }
                    $articles[] = array(
                        'title' => (string)$entry->title,
                        'url'   => $link,
                    );
                }
            }
        } catch (Exception $e) {
            $this->log("RSS解析异常: " . $e->getMessage());
        }

        $this->log("RSS解析到 " . count($articles) . " 篇文章");
        return $articles;
    }

    /**
     * 方法3: 手动URL采集
     */
    private function collect_from_manual_urls($options) {
        $urls_text = isset($options['manual_urls']) ? $options['manual_urls'] : '';
        if (empty($urls_text)) return array();

        $articles = array();
        $lines = array_filter(explode("\n", $urls_text));

        foreach ($lines as $line) {
            $line = trim($line);
            if (empty($line) || strpos($line, '#') === 0) continue;

            // 支持格式: URL 或 标题|URL
            if (strpos($line, '|') !== false) {
                list($title, $url) = array_map('trim', explode('|', $line, 2));
            } else {
                $url = $line;
                $title = '';
            }

            if (filter_var($url, FILTER_VALIDATE_URL)) {
                $articles[] = array('title' => $title, 'url' => $url);
            }
        }

        $this->log("手动URL解析到 " . count($articles) . " 篇文章");
        return $articles;
    }

    /**
     * 采集微信文章正文内容
     */
    private function fetch_article_content($url) {
        $this->log("获取文章内容: " . mb_substr($url, 0, 80));

        $response = wp_remote_get($url, array(
            'timeout'    => 30,
            'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            'headers'    => array(
                'Accept'          => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'Accept-Language' => 'zh-CN,zh;q=0.9',
            ),
        ));

        if (is_wp_error($response)) {
            $this->log("请求失败: " . $response->get_error_message());
            return false;
        }

        $html = wp_remote_retrieve_body($response);
        if (empty($html)) {
            $this->log("返回内容为空");
            return false;
        }

        return $this->parse_wechat_article($html);
    }

    /**
     * 解析微信文章HTML
     */
    private function parse_wechat_article($html) {
        $content = array(
            'title'   => '',
            'author'  => '',
            'body'    => '',
            'cover'   => '',
            'date'    => '',
        );

        // 提取标题（优先使用og:title，因为微信文章标题可能是动态加载的）
        if (preg_match('/<meta\s+property="og:title"\s+content="([^"]+)"/i', $html, $m)) {
            $content['title'] = html_entity_decode($m[1], ENT_QUOTES, 'UTF-8');
        } elseif (preg_match('/<meta\s+name="title"\s+content="([^"]+)"/i', $html, $m)) {
            $content['title'] = html_entity_decode($m[1], ENT_QUOTES, 'UTF-8');
        } elseif (preg_match('/<h1[^>]*class="rich_media_title"[^>]*>(.*?)<\/h1>/s', $html, $m)) {
            $content['title'] = trim(wp_strip_all_tags($m[1]));
        } elseif (preg_match('/<title>(.*?)<\/title>/s', $html, $m)) {
            $content['title'] = trim(wp_strip_all_tags($m[1]));
        }

        // 提取作者/公众号名
        if (preg_match('/<a[^>]*id="js_name"[^>]*>(.*?)<\/a>/s', $html, $m)) {
            $content['author'] = trim(wp_strip_all_tags($m[1]));
        } elseif (preg_match('/var\s+nickname\s*=\s*["\']([^"\']+)/', $html, $m)) {
            $content['author'] = trim($m[1]);
        }

        // 提取正文内容（使用更可靠的方法）
        $body = '';
        
        // 方法1: 查找 rich_media_content 或 js_content 容器
        if (preg_match('/<div[^>]*(?:class="rich_media_content[^"]*"|id="js_content")[^>]*>/i', $html, $start_match)) {
            $start_pos = strpos($html, $start_match[0]);
            if ($start_pos !== false) {
                // 从开始位置查找结束标记
                $end_markers = array(
                    '<div class="ct_mpda_wrp"',
                    '<div class="like_area"',
                    '<div class="reward_area"',
                    '<script>',
                    '<script ',
                    '</article>',
                );
                
                $end_pos = strlen($html);
                foreach ($end_markers as $marker) {
                    $pos = strpos($html, $marker, $start_pos + strlen($start_match[0]));
                    if ($pos !== false && $pos < $end_pos) {
                        $end_pos = $pos;
                    }
                }
                
                $body = substr($html, $start_pos + strlen($start_match[0]), $end_pos - $start_pos - strlen($start_match[0]));
            }
        }
        
        // 方法2: 备用方案 - 使用正则提取
        if (empty($body) && preg_match('/<div[^>]*class="rich_media_content[^"]*"[^>]*>(.*)/s', $html, $m)) {
            $body = $m[1];
            // 截取到第一个结束标记
            foreach (array('<div class="ct_mpda_wrp"', '<script', '</article>') as $marker) {
                $pos = strpos($body, $marker);
                if ($pos !== false) {
                    $body = substr($body, 0, $pos);
                    break;
                }
            }
        }

        if (!empty($body)) {
            // 清理微信特有的样式和属性
            $body = $this->clean_wechat_html($body);
            // 下载微信图片到本地
            $body = $this->localize_wechat_images($body);
            $content['body'] = $body;
        }

        // 提取封面图
        if (preg_match('/var\s+cover\s*=\s*["\']([^"\']+)/', $html, $m)) {
            $content['cover'] = trim($m[1], '"\'');
        } elseif (preg_match('/og:image"\s+content="([^"]+)"/', $html, $m)) {
            $content['cover'] = $m[1];
        }

        // 提取发布时间
        if (preg_match('/var\s+ct\s*=\s*["\']?(\d+)/', $html, $m)) {
            $content['date'] = date('Y-m-d H:i:s', intval($m[1]));
        } elseif (preg_match('/<em[^>]*id="publish_time"[^>]*>(.*?)<\/em>/s', $html, $m)) {
            $content['date'] = trim(wp_strip_all_tags($m[1]));
        }

        return $content;
    }

    /**
     * 清理微信文章HTML
     */
    private function clean_wechat_html($html) {
        // 移除data-*属性（保留data-src转为src）
        $html = preg_replace_callback('/data-src="([^"]*)"/', function($m) {
            return 'src="' . esc_url($m[1]) . '"';
        }, $html);

        // 移除其他data-*属性
        $html = preg_replace('/\s+data-[a-z\-]+="[^"]*"/i', '', $html);

        // 移除visibility:hidden样式
        $html = preg_replace('/visibility:\s*hidden;?/i', '', $html);

        // 移除空的style属性
        $html = preg_replace('/\s+style=""/', '', $html);

        // 移除微信特有的标签和类
        $html = preg_replace('/<mpvoice[^>]*>.*?<\/mpvoice>/is', '', $html);
        $html = preg_replace('/<mp-miniprogram[^>]*>.*?<\/mp-miniprogram>/is', '', $html);
        $html = preg_replace('/<mp-common-product[^>]*>.*?<\/mp-common-product>/is', '', $html);

        // 移除script标签
        $html = preg_replace('/<script[^>]*>.*?<\/script>/is', '', $html);

        // 移除class中的微信特有类名（保留基本样式）
        $html = preg_replace('/\s+class="[^"]*"/', '', $html);

        return trim($html);
    }

    /**
     * 下载微信图片到本地服务器
     */
    private function localize_wechat_images($html) {
        // 先解码HTML实体，避免&quot;等影响URL匹配
        $html = html_entity_decode($html, ENT_QUOTES, 'UTF-8');
        
        // 匹配所有微信图片URL（包括mmbiz和mmecoa域名，以及src和background-image）
        preg_match_all('/(?:src|url)\s*[\(=]\s*["\']?(https:\/\/(?:mmbiz|mmecoa)\.qpic\.cn\/[^"\'\)\s]+)/i', $html, $matches);

        if (empty($matches[1])) {
            return $html;
        }

        // 去重
        $unique_urls = array_unique($matches[1]);
        $this->log("发现 " . count($unique_urls) . " 张微信图片，开始本地化...");

        require_once(ABSPATH . 'wp-admin/includes/media.php');
        require_once(ABSPATH . 'wp-admin/includes/file.php');
        require_once(ABSPATH . 'wp-admin/includes/image.php');

        $upload_dir = wp_upload_dir();
        $image_cache = array(); // 缓存已下载的图片，避免重复下载

        foreach ($unique_urls as $wechat_url) {
            // 检查是否已处理过
            if (isset($image_cache[$wechat_url])) {
                // 替换所有出现的位置（包括src和background-image）
                $html = str_replace($wechat_url, $image_cache[$wechat_url], $html);
                continue;
            }

            // 下载图片
            $tmp_file = download_url($wechat_url, 30);

            if (is_wp_error($tmp_file)) {
                $this->log("图片下载失败: " . $tmp_file->get_error_message());
                continue;
            }

            // 获取文件扩展名
            $file_info = wp_check_filetype(basename(parse_url($wechat_url, PHP_URL_PATH)));
            $ext = $file_info['ext'] ? $file_info['ext'] : 'jpg';

            // 生成唯一文件名
            $filename = 'wechat-' . md5($wechat_url) . '.' . $ext;
            $file_path = $upload_dir['path'] . '/' . $filename;

            // 移动临时文件到上传目录
            if (rename($tmp_file, $file_path)) {
                // 创建WordPress附件
                $attachment = array(
                    'post_mime_type' => $file_info['type'] ?: 'image/jpeg',
                    'post_title'     => sanitize_file_name($filename),
                    'post_content'   => '',
                    'post_status'    => 'inherit'
                );

                $attach_id = wp_insert_attachment($attachment, $file_path);

                if (!is_wp_error($attach_id)) {
                    // 生成缩略图
                    require_once(ABSPATH . 'wp-admin/includes/image.php');
                    wp_update_attachment_metadata($attach_id, wp_generate_attachment_metadata($attach_id, $file_path));

                    // 获取本地图片URL
                    $local_url = wp_get_attachment_url($attach_id);
                    $image_cache[$wechat_url] = $local_url;

                    // 替换HTML中的图片链接
                    $html = str_replace($wechat_url, $local_url, $html);
                    $this->log("✓ 图片已本地化: " . basename($local_url));
                } else {
                    @unlink($file_path);
                }
            } else {
                @unlink($tmp_file);
            }

            // 避免请求过快
            usleep(500000); // 0.5秒
        }

        $this->log("图片本地化完成，共处理 " . count($image_cache) . " 张图片（原" . count($matches[1]) . "个引用）");
        return $html;
    }

    /**
     * 创建WordPress文章
     */
    private function create_post($article, $content_data, $options) {
        $title = !empty($content_data['title']) ? $content_data['title'] : $article['title'];
        $body = $content_data['body'];

        if (empty($title) || empty($body)) {
            $this->log("标题或内容为空，跳过");
            return false;
        }

        // 添加来源信息
        $source_note = '<div style="margin-top:20px;padding:12px 16px;background:#f5f7fa;border-left:3px solid #0281cc;border-radius:4px;font-size:14px;color:#666;">';
        $source_note .= '<p style="margin:0;">来源：' . esc_html($content_data['author'] ?: $options['account_name']);
        if (!empty($content_data['date'])) {
            $source_note .= ' | 发布时间：' . esc_html($content_data['date']);
        }
        $source_note .= '</p>';
        $source_note .= '<p style="margin:4px 0 0;"><a href="' . esc_url($article['url']) . '" target="_blank" rel="nofollow">查看原文</a></p>';
        $source_note .= '</div>';

        $full_content = $body . "\n" . $source_note;

        // 构建文章数据
        $post_data = array(
            'post_title'   => wp_strip_all_tags($title),
            'post_content' => $full_content,
            'post_status'  => isset($options['post_status']) ? $options['post_status'] : 'publish',
            'post_type'    => 'post',
            'post_date'    => !empty($content_data['date']) ? $content_data['date'] : current_time('mysql'),
        );

        // 设置分类
        if (!empty($options['target_category'])) {
            $post_data['post_category'] = array(intval($options['target_category']));
        }

        $post_id = wp_insert_post($post_data, true);

        if (is_wp_error($post_id)) {
            $this->log("创建文章失败: " . $post_id->get_error_message());
            return false;
        }

        // 设置特色图片
        if (!empty($content_data['cover'])) {
            $this->set_featured_image($post_id, $content_data['cover']);
        }

        // 添加自定义字段
        update_post_meta($post_id, '_wechat_source_url', $article['url']);
        update_post_meta($post_id, '_wechat_account', $content_data['author'] ?: $options['account_name']);
        update_post_meta($post_id, '_wechat_collected_at', current_time('mysql'));

        return $post_id;
    }

    /**
     * 设置特色图片
     */
    private function set_featured_image($post_id, $image_url) {
        if (empty($image_url)) return;

        require_once(ABSPATH . 'wp-admin/includes/media.php');
        require_once(ABSPATH . 'wp-admin/includes/file.php');
        require_once(ABSPATH . 'wp-admin/includes/image.php');

        $tmp = download_url($image_url, 30);
        if (is_wp_error($tmp)) {
            $this->log("下载封面图失败: " . $tmp->get_error_message());
            return;
        }

        $file_array = array(
            'name'     => basename(parse_url($image_url, PHP_URL_PATH)),
            'tmp_name' => $tmp,
        );

        $attachment_id = media_handle_sideload($file_array, $post_id);
        if (!is_wp_error($attachment_id)) {
            set_post_thumbnail($post_id, $attachment_id);
        } else {
            @unlink($tmp);
        }
    }

    // ==========================================
    //  去重机制
    // ==========================================

    /**
     * 检查文章是否已采集
     */
    private function is_collected($url) {
        global $wpdb;

        $hash = md5($url);
        $table = $wpdb->prefix . 'wechat_collected';

        // 检查数据库记录
        $exists = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM $table WHERE article_hash = %s",
            $hash
        ));

        if ($exists > 0) return true;

        // 检查是否已存在相同来源URL的文章
        $post_exists = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->postmeta} WHERE meta_key = '_wechat_source_url' AND meta_value = %s",
            $url
        ));

        return $post_exists > 0;
    }

    /**
     * 记录已采集文章
     */
    private function record_collected($url, $title, $post_id) {
        global $wpdb;

        $wpdb->insert($wpdb->prefix . 'wechat_collected', array(
            'article_url'   => $url,
            'article_title' => $title,
            'article_hash'  => md5($url),
            'post_id'       => $post_id,
            'collected_at'  => current_time('mysql'),
            'status'        => 'success',
        ));
    }

    // ==========================================
    //  日志系统
    // ==========================================

    private function log($message) {
        $log_file = WAC_PLUGIN_DIR . 'collector.log';
        $time = current_time('Y-m-d H:i:s');
        file_put_contents($log_file, "[{$time}] {$message}\n", FILE_APPEND);
    }

    /**
     * 获取日志
     */
    public function get_logs($lines = 50) {
        $log_file = WAC_PLUGIN_DIR . 'collector.log';
        if (!file_exists($log_file)) return '';

        $all_lines = file($log_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        $recent = array_slice($all_lines, -$lines);
        return implode("\n", $recent);
    }

    // ==========================================
    //  AJAX处理
    // ==========================================

    /**
     * 手动执行采集
     */
    public function ajax_manual_collect() {
        check_ajax_referer('wac_ajax_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error('权限不足');
        }

        $this->run_collection();

        wp_send_json_success(array(
            'message' => '采集任务已执行完成',
            'logs'    => $this->get_logs(30),
        ));
    }

    /**
     * 采集单个URL
     */
    public function ajax_collect_single_url() {
        check_ajax_referer('wac_ajax_nonce', 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error('权限不足');
        }

        $url = isset($_POST['url']) ? esc_url_raw(trim($_POST['url'])) : '';
        if (empty($url)) {
            wp_send_json_error('请输入文章URL');
        }

        if ($this->is_collected($url)) {
            wp_send_json_error('该文章已采集过');
        }

        $options = get_option($this->option_name);
        $content = $this->fetch_article_content($url);

        if (!$content || empty($content['body'])) {
            wp_send_json_error('无法获取文章内容，请检查URL是否正确');
        }

        $article = array('title' => $content['title'], 'url' => $url);
        $post_id = $this->create_post($article, $content, $options);

        if ($post_id) {
            $this->record_collected($url, $content['title'], $post_id);
            $this->log("手动采集成功: {$content['title']} (ID: {$post_id})");

            wp_send_json_success(array(
                'message' => '采集成功',
                'post_id' => $post_id,
                'title'   => $content['title'],
                'edit_url' => admin_url("post.php?post={$post_id}&action=edit"),
            ));
        } else {
            wp_send_json_error('文章创建失败');
        }
    }

    /**
     * 获取日志
     */
    public function ajax_get_logs() {
        check_ajax_referer('wac_ajax_nonce', 'nonce');
        wp_send_json_success(array('logs' => $this->get_logs(100)));
    }

    /**
     * 清除日志
     */
    public function ajax_clear_logs() {
        check_ajax_referer('wac_ajax_nonce', 'nonce');
        $log_file = WAC_PLUGIN_DIR . 'collector.log';
        file_put_contents($log_file, '');
        wp_send_json_success(array('message' => '日志已清除'));
    }

    // ==========================================
    //  后台页面渲染
    // ==========================================

    public function render_admin_page() {
        $options = get_option($this->option_name);
        global $wpdb;

        // 获取已采集统计
        $total_collected = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}wechat_collected WHERE status='success'");

        // 获取分类列表
        $categories = get_categories(array('hide_empty' => 0));

        // 获取页面列表
        $pages = get_pages(array('sort_column' => 'title'));

        include WAC_PLUGIN_DIR . 'admin-page.php';
    }
}

// 初始化插件
WeChat_Article_Collector::get_instance();
