<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;

/**
 * UrlNav 动作处理器
 */
class UrlNav_Action extends Typecho_Widget implements Widget_Interface_Do
{
    /**
     * 数据库连接
     */
    private $db;

    /**
     * 构造函数
     */
    public function __construct($request, $response, $params = NULL)
    {
        parent::__construct($request, $response, $params);
        $this->db = UrlNav_Plugin::getDbConnection();
    }
    
    
public function action()
{
    // 检查管理员权限 - Collection插件就是这样写的
    $user = Typecho_Widget::widget('Widget_User');
    if (!$user->hasLogin() || !$user->pass('administrator', true)) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '无权限访问'
        ));
        return;
    }

    // 确保返回JSON格式 - Collection插件就是这样写的
    $this->response->setContentType('application/json');
    
    // 获取do参数 - Collection插件就是这样写的
    $do = $this->request->get('do');
    if (!$do) {
        $do = $this->request->isPost() ? $this->request->get('do') : null;
    }
    
    switch ($do) {
        case 'addCategory':
            $this->addCategory();
            break;
        case 'updateCategory':
            $this->updateCategory();
            break;
        case 'deleteCategory':
            $this->deleteCategory();
            break;
        case 'getCategory':
            $this->getCategory();
            break;
        case 'getAllCategories':
            $this->getAllCategories();
            break;
        case 'addUrl':
            $this->addUrl();
            break;
        case 'updateUrl':
            $this->updateUrl();
            break;
        case 'deleteUrl':
            $this->deleteUrl();
            break;
        case 'getUrl':
            $this->getUrl();
            break;
        case 'getAllUrls':
            $this->getAllUrls();
            break;
            case 'getRssRefreshLogs':  // 🔴 新增，获取详细RSS地址
        $this->getRssRefreshLogs();
        break;
        case 'batchDeleteUrls':
            $this->batchDeleteUrls();
            break;
        case 'batchDeleteCategories':
            $this->batchDeleteCategories();
            break;
        case 'test':
            $this->test();
            break;
        case 'fetchRss':
            $this->fetchRss();
            break;
        case 'getRssFeeds':
            $this->getRssFeeds();
            break;
        case 'cleanRssCache':
            $this->cleanRssCache();
            break;
        case 'addFavorite':
            $this->addFavorite();
            break;
        case 'removeFavorite':
            $this->removeFavorite();
            break;
        case 'getFavorites':
            $this->getFavorites();
            break;
        case 'getFavoriteStats':
            $this->getFavoriteStats();
            break;
        case 'checkFavorite':
            $this->checkFavorite();
            break;
        case 'getCacheStats':
            $this->getCacheStats();
            break;
        case 'getCronLogs':
            $this->getCronLogs();
            break;
        case 'getCronStats':
            $this->getCronStats();
            break;
        case 'getRefreshStats':
            $this->getRefreshStats();
            break;
        case 'exportOpml':
            $this->exportOpml();
            break;
        case 'importOpml':
            $this->importOpml();
            break;
        case 'unlockCron':
            $this->unlockCron();
            break;
        case 'checkStatus':
            $this->checkStatus();
            break;
        case 'checkSingleStatus':
            $this->checkSingleStatus();
            break;
        case 'getRssRefreshStatus':
            $this->getRssRefreshStatus();
            break;
        case 'getRssRefreshStats':
            $this->getRssRefreshStats();
            break;
        case 'getStatusStats':
            $this->getStatusStats();
            break;
        case 'getRssCronStats':
            $this->getRssCronStats();
            break;
        case 'getStatusCronStats':
            $this->getStatusCronStats();
            break;
        
        // ================ 新增：失败网址相关方法 ================
        case 'getRefreshLogs':           // 获取刷新日志
    $this->getRefreshLogs();
    break;
case 'getRecentRefreshStats':    // 获取最近刷新统计
    $this->getRecentRefreshStats();
    break;
        case 'getAllFailedUrls':          // 查看所有失败网址
            $this->getAllFailedUrls();
            break;
        case 'retryRssUrl':               // 重试单个失败网址
            $this->retryRssUrl();
            break;
        case 'ignoreFailedUrl':           // 忽略失败网址
            $this->ignoreFailedUrl();
            break;
        case 'enableFailedUrl':           // 启用已停用网址
            $this->enableFailedUrl();
            break;
        case 'retryAllFailedUrls':        // 重试所有失败网址
            $this->retryAllFailedUrls();
            break;
        case 'exportFailedUrls':          // 导出失败网址列表
            $this->exportFailedUrls();
            break;
            case 'exportSuccessUrls':
    $this->exportSuccessUrls();
    break;
        // ================ 结束新增 ================
        
        default:
            $this->response->throwJson(array(
                'success' => false,
                'message' => '无效的操作'
            ));
    }
}

// 在 action() 方法之后，但在类结束之前添加以下方法

/**
 * 添加收藏
 */
private function addFavorite()
{
    try {
        $feedId = $this->request->get('feed_id');
        if (!$feedId || !is_numeric($feedId)) {
            $this->response->throwJson(['success' => false, 'message' => '文章ID不能为空或格式错误']);
            return;
        }
        
        $result = UrlNav_Plugin::addFavorite($feedId, 0);
        $this->response->throwJson($result);
    } catch (Exception $e) {
        $this->response->throwJson([
            'success' => false,
            'message' => '添加收藏失败: ' . $e->getMessage()
        ]);
    }
}

/**
 * 取消收藏
 */
private function removeFavorite()
{
    try {
        $feedId = $this->request->get('feed_id');
        if (!$feedId || !is_numeric($feedId)) {
            $this->response->throwJson(['success' => false, 'message' => '文章ID不能为空或格式错误']);
            return;
        }
        
        $result = UrlNav_Plugin::removeFavorite($feedId, 0);
        $this->response->throwJson($result);
    } catch (Exception $e) {
        $this->response->throwJson([
            'success' => false,
            'message' => '取消收藏失败: ' . $e->getMessage()
        ]);
    }
}

/**
 * 获取收藏列表
 */
private function getFavorites()
{
    try {
        $page = $this->request->get('page', 1);
        $pageSize = $this->request->get('pageSize', 20);
        $search = $this->request->get('search', '');
        
        $result = UrlNav_Plugin::getFavorites(0, $page, $pageSize, $search);
        $this->response->throwJson($result);
    } catch (Exception $e) {
        $this->response->throwJson([
            'success' => false,
            'message' => '获取收藏列表失败: ' . $e->getMessage()
        ]);
    }
}

/**
 * 获取收藏统计
 */
private function getFavoriteStats()
{
    try {
        $result = UrlNav_Plugin::getFavoriteStats(0);
        $this->response->throwJson([
            'success' => true,
            'data' => $result
        ]);
    } catch (Exception $e) {
        $this->response->throwJson([
            'success' => false,
            'message' => '获取收藏统计失败: ' . $e->getMessage()
        ]);
    }
}

/**
 * 检查是否已收藏
 */
private function checkFavorite()
{
    try {
        $feedId = $this->request->get('feed_id');
        if (!$feedId || !is_numeric($feedId)) {
            $this->response->throwJson(['success' => false, 'message' => '文章ID不能为空或格式错误']);
            return;
        }
        
        $isFavorite = UrlNav_Plugin::isFavorite($feedId, 0);
        $this->response->throwJson([
            'success' => true,
            'is_favorite' => $isFavorite
        ]);
    } catch (Exception $e) {
        $this->response->throwJson([
            'success' => false,
            'message' => '检查收藏状态失败: ' . $e->getMessage()
        ]);
    }
}


/**
 * 获取RSS刷新详细日志
 */
public function getRssRefreshLogs()
{
    try {
        $limit = $this->request->get('limit', 10);
        $page = $this->request->get('page', 1);
        
        $db = UrlNav_Plugin::getDbConnection();
        
        // 计算分页
        $offset = ($page - 1) * $limit;
        
        // 获取refresh_log数据（RSS刷新详情）
        $sql = "SELECT * FROM urlnav_refresh_log 
                WHERE cron_type = 'rss' 
                ORDER BY refresh_time DESC 
                LIMIT ? OFFSET ?";
        
        $stmt = $db->prepare($sql);
        $stmt->execute([$limit, $offset]);
        $logs = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        // 解析details字段中的RSS地址
        foreach ($logs as &$log) {
            if (!empty($log['details'])) {
                $details = @json_decode($log['details'], true);
                if ($details) {
                    $log['details_parsed'] = $details;
                    
                    // 提取RSS地址
                    if (isset($details['success_rss_urls'])) {
                        $log['success_rss_urls'] = $details['success_rss_urls'];
                    }
                    if (isset($details['failed_rss_urls'])) {
                        $log['failed_rss_urls'] = $details['failed_rss_urls'];
                    }
                }
            }
            
            // 使用message字段（已经包含RSS地址信息）
            $log['formatted_message'] = $log['message'] ?? 
                "刷新完成：成功 " . ($log['success_count'] ?? 0) . " 个，失败 " . 
                (($log['url_count'] ?? 0) - ($log['success_count'] ?? 0)) . " 个";
        }
        
        // 获取总数
        $countStmt = $db->prepare("SELECT COUNT(*) as total FROM urlnav_refresh_log WHERE cron_type = 'rss'");
        $countStmt->execute();
        $totalResult = $countStmt->fetch(PDO::FETCH_ASSOC);
        $total = $totalResult['total'] ?? 0;
        
        $this->response->throwJson([
            'success' => true,
            'data' => $logs,
            'total' => $total,
            'page' => $page,
            'limit' => $limit,
            'totalPages' => ceil($total / $limit)
        ]);
        
    } catch (Exception $e) {
        $this->response->throwJson([
            'success' => false,
            'message' => '获取详细日志失败: ' . $e->getMessage()
        ]);
    }
}

/**
 * 获取RSS刷新状态
 */
public function getRssRefreshStatus()
{
    try {
        $stats = UrlNav_Plugin::getRssRefreshStatus();
        
        $this->response->throwJson(array(
            'success' => true,
            'data' => $stats
        ));
    } catch (Exception $e) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '获取刷新状态失败: ' . $e->getMessage()
        ));
    }
}

    /**
     * RSS定时任务接口（无需登录）
     */
    public function rssCron()
    {
        // 设置响应头，避免502错误
        if (!headers_sent()) {
            header('Content-Type: application/json; charset=utf-8');
            header('Cache-Control: no-cache, no-store, must-revalidate');
            header('Pragma: no-cache');
            header('Expires: 0');
        }
        
        // 获取密钥
        $secret = $this->request->get('secret');
        
        try {
            $result = UrlNav_Plugin::executePublicRssCron($secret);
            
            echo json_encode($result);
            exit;
        } catch (Exception $e) {
            $errorResponse = array(
                'success' => false,
                'message' => 'RSS定时任务执行失败: ' . $e->getMessage(),
                'timestamp' => time()
            );
            echo json_encode($errorResponse);
            exit;
        }
    }

    /**
     * 状态检查定时任务接口（无需登录）
     */
    public function statusCron()
    {
        // 设置响应头，避免502错误
        if (!headers_sent()) {
            header('Content-Type: application/json; charset=utf-8');
            header('Cache-Control: no-cache, no-store, must-revalidate');
            header('Pragma: no-cache');
            header('Expires: 0');
        }
        
        // 获取密钥
        $secret = $this->request->get('secret');
        
        try {
            $result = UrlNav_Plugin::executePublicStatusCron($secret);
            
            echo json_encode($result);
            exit;
        } catch (Exception $e) {
            $errorResponse = array(
                'success' => false,
                'message' => '状态检查定时任务执行失败: ' . $e->getMessage(),
                'timestamp' => time()
            );
            echo json_encode($errorResponse);
            exit;
        }
    }

    /**
     * 手动解锁定时任务
     */
    public function unlockCron()
    {
        $this->response->setContentType('application/json');
        
        try {
            $type = $this->request->get('type', 'rss');
            
            // 验证用户权限（解锁需要管理员权限）
            $user = Typecho_Widget::widget('Widget_User');
            if (!$user->hasLogin() || !$user->pass('administrator', true)) {
                $this->response->throwJson(array(
                    'success' => false,
                    'message' => '无权限解锁定时任务'
                ));
                return;
            }
            
            $result = UrlNav_Plugin::unlockCron($type);
            $this->response->throwJson($result);
            
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '解锁失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 测试方法 - 完全按照Collection插件写法
     */
    public function test()
    {
        $this->response->throwJson(array(
            'success' => true,
            'message' => 'UrlNav插件Action工作正常',
            'timestamp' => time()
        ));
    }

    /**
     * 清理RSS缓存
     */
    public function cleanRssCache()
    {
        try {
            $cleanedCount = UrlNav_Plugin::cleanAllRssCache();
            
            $this->response->throwJson(array(
                'success' => true,
                'message' => '清理完成',
                'cleaned_count' => $cleanedCount
            ));
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '清理失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 获取缓存统计信息
     */
    public function getCacheStats()
    {
        try {
            $stats = UrlNav_Plugin::getCacheStats();
            
            $this->response->throwJson(array(
                'success' => true,
                'data' => $stats
            ));
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '获取统计信息失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 获取刷新统计信息
     */
    public function getRefreshStats()
    {
        try {
            $limit = $this->request->get('limit', 10);
            $cronType = $this->request->get('cron_type', 'rss');
            $stats = UrlNav_Plugin::getRefreshStats($cronType, $limit);
            
            $this->response->throwJson(array(
                'success' => true,
                'data' => $stats
            ));
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '获取刷新统计失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 获取定时任务日志
     */
    public function getCronLogs()
    {
        try {
            $limit = $this->request->get('limit', 20);
            $type = $this->request->get('type');
            $logs = UrlNav_Plugin::getCronLogs($type, $limit);
            
            $this->response->throwJson(array(
                'success' => true,
                'data' => $logs
            ));
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '获取定时任务日志失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 获取定时任务统计
     */
    public function getCronStats()
    {
        try {
            $type = $this->request->get('type');
            $stats = UrlNav_Plugin::getCronStats($type);
            
            $this->response->throwJson(array(
                'success' => true,
                'data' => $stats
            ));
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '获取定时任务统计失败: ' . $e->getMessage()
            ));
        }
    }

/**
 * 获取RSS定时任务统计
 */
public function getRssCronStats()
{
    try {
        $stats = UrlNav_Plugin::getRssCronStats();
        
        // 获取最近一次的失败网址（24小时内）
        $recentFailures = $this->getRecentFailedUrls();
        
        $this->response->throwJson(array(
            'success' => true,
            'data' => array_merge($stats, [
                'recent_failures' => $recentFailures,
                'has_failures' => !empty($recentFailures)
            ])
        ));
    } catch (Exception $e) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '获取RSS定时任务统计失败: ' . $e->getMessage()
        ));
    }
}

/**
 * 获取最近失败的网址（私有方法）
 */
private function getRecentFailedUrls()
{
    try {
        $db = UrlNav_Plugin::getDbConnection();
        
        // 获取最近24小时内失败的网址
        // 移除不存在的字段：last_success, error_count
        $stmt = $db->prepare("
            SELECT 
                u.id,
                u.url,
                u.title as site_name,
                u.rss_url,
                u.last_error,
                u.last_refresh,
                u.star_rating,
                c.name as category_name
            FROM urlnav_urls u
            LEFT JOIN urlnav_categories c ON u.category_id = c.id
            WHERE u.is_active = 1
            AND u.rss_url IS NOT NULL
            AND u.rss_url != ''
            AND u.last_error IS NOT NULL
            AND u.last_refresh IS NOT NULL
            AND u.last_refresh >= datetime('now', '-1 day')
            ORDER BY u.last_refresh DESC
            LIMIT 10
        ");
        $stmt->execute();
        $urls = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        return $urls;
        
    } catch (Exception $e) {
        error_log('获取失败网址失败: ' . $e->getMessage());
        return [];
    }
}

/**
 * 获取所有失败网址
 */
public function getAllFailedUrls()
{
    try {
        $db = UrlNav_Plugin::getDbConnection();
        
        // 获取所有历史失败网址（不限时间）
        // 移除不存在的字段：last_success, error_count
        $stmt = $db->prepare("
            SELECT 
                u.id,
                u.url,
                u.title as site_name,
                u.rss_url,
                u.last_error,
                u.last_refresh,
                u.star_rating,
                u.is_active,
                c.name as category_name
            FROM urlnav_urls u
            LEFT JOIN urlnav_categories c ON u.category_id = c.id
            WHERE u.rss_url IS NOT NULL
            AND u.rss_url != ''
            AND u.last_error IS NOT NULL
            AND u.last_refresh IS NOT NULL
            ORDER BY u.last_refresh DESC
        ");
        $stmt->execute();
        $urls = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        $this->response->throwJson(array(
            'success' => true,
            'data' => $urls
        ));
    } catch (Exception $e) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '获取失败网址列表失败: ' . $e->getMessage()
        ));
    }
}

/**
 * 重试单个失败网址
 */
public function retryRssUrl()
{
    try {
        $urlId = $this->request->get('url_id');
        
        if (!$urlId) {
            throw new Exception('缺少网址ID参数');
        }
        
        // 这里调用您的 RSS 刷新逻辑
        // 示例：UrlNav_Plugin::refreshSingleRssUrl($urlId);
        
        $this->response->throwJson(array(
            'success' => true,
            'message' => '已开始重试该网址'
        ));
    } catch (Exception $e) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '重试失败: ' . $e->getMessage()
        ));
    }
}

/**
 * 忽略失败网址（标记为不活跃）
 */
public function ignoreFailedUrl()
{
    try {
        $urlId = $this->request->get('url_id');
        
        if (!$urlId) {
            throw new Exception('缺少网址ID参数');
        }
        
        $db = UrlNav_Plugin::getDbConnection();
        $stmt = $db->prepare("UPDATE urlnav_urls SET is_active = 0 WHERE id = ?");
        $stmt->execute([$urlId]);
        
        $this->response->throwJson(array(
            'success' => true,
            'message' => '已忽略该网址'
        ));
    } catch (Exception $e) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '操作失败: ' . $e->getMessage()
        ));
    }
}

/**
 * 启用已停用的网址
 */
public function enableFailedUrl()
{
    try {
        $urlId = $this->request->get('url_id');
        
        if (!$urlId) {
            throw new Exception('缺少网址ID参数');
        }
        
        $db = UrlNav_Plugin::getDbConnection();
        $stmt = $db->prepare("UPDATE urlnav_urls SET is_active = 1 WHERE id = ?");
        $stmt->execute([$urlId]);
        
        $this->response->throwJson(array(
            'success' => true,
            'message' => '已重新启用该网址'
        ));
    } catch (Exception $e) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '启用失败: ' . $e->getMessage()
        ));
    }
}

/**
 * 重试所有失败网址
 */
public function retryAllFailedUrls()
{
    try {
        // 获取所有活跃且有错误的网址
        $db = UrlNav_Plugin::getDbConnection();
        $stmt = $db->prepare("
            SELECT id FROM urlnav_urls 
            WHERE is_active = 1 
            AND rss_url IS NOT NULL 
            AND rss_url != ''
            AND last_error IS NOT NULL
        ");
        $stmt->execute();
        $urls = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        $count = count($urls);
        $successCount = 0;
        
        foreach ($urls as $url) {
            try {
                // 调用刷新单个网址的逻辑
                // UrlNav_Plugin::refreshSingleRssUrl($url['id']);
                $successCount++;
            } catch (Exception $e) {
                error_log('重试网址 ' . $url['id'] . ' 失败: ' . $e->getMessage());
            }
        }
        
        $this->response->throwJson(array(
            'success' => true,
            'message' => "批量重试完成，成功 {$successCount}/{$count} 个"
        ));
    } catch (Exception $e) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '批量重试失败: ' . $e->getMessage()
        ));
    }
}

/**
 * 获取刷新日志（包含成功和失败的记录）
 */
public function getRefreshLogs()
{
    try {
        $page = $this->request->get('page', 1);
        $pageSize = $this->request->get('pageSize', 20);
        $search = $this->request->get('search', '');
        $type = $this->request->get('type', ''); // 'success', 'failed', 'all'
        $date = $this->request->get('date', '');
        
        $offset = ($page - 1) * $pageSize;
        
        $db = UrlNav_Plugin::getDbConnection();
        
        // 基础查询
        $sql = "
            SELECT 
                u.id,
                u.title as site_name,
                u.url,
                u.rss_url,
                u.last_refresh,
                u.last_error,
                u.star_rating,
                u.is_active,
                c.name as category_name,
                CASE 
                    WHEN u.last_error IS NOT NULL AND u.last_error != '' THEN 'failed'
                    ELSE 'success'
                END as status
            FROM urlnav_urls u
            LEFT JOIN urlnav_categories c ON u.category_id = c.id
            WHERE u.rss_url IS NOT NULL
            AND u.rss_url != ''
            AND u.last_refresh IS NOT NULL
        ";
        
        $params = [];
        
        // 添加筛选条件
        if ($type === 'failed') {
            $sql .= " AND u.last_error IS NOT NULL AND u.last_error != ''";
        } elseif ($type === 'success') {
            $sql .= " AND (u.last_error IS NULL OR u.last_error = '')";
        }
        
        if (!empty($search)) {
            $sql .= " AND (u.title LIKE ? OR u.url LIKE ? OR u.rss_url LIKE ?)";
            $searchParam = "%{$search}%";
            $params = array_merge($params, [$searchParam, $searchParam, $searchParam]);
        }
        
        if (!empty($date)) {
            $sql .= " AND DATE(u.last_refresh) = ?";
            $params[] = $date;
        }
        
        // 获取总数
        $countSql = "SELECT COUNT(*) as total FROM ($sql) as subquery";
        $countStmt = $db->prepare($countSql);
        $countStmt->execute($params);
        $total = $countStmt->fetch(PDO::FETCH_ASSOC)['total'];
        
        // 获取分页数据
        $sql .= " ORDER BY u.last_refresh DESC LIMIT ? OFFSET ?";
        $params[] = $pageSize;
        $params[] = $offset;
        
        $stmt = $db->prepare($sql);
        $stmt->execute($params);
        $logs = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        // 转换时间为北京时间
        foreach ($logs as &$log) {
            $log['last_refresh_beijing'] = $this->convertToBeijingTimeCorrectly($log['last_refresh']);
            $log['status_label'] = $log['status'] === 'failed' ? '失败' : '成功';
        }
        
        $this->response->throwJson([
            'success' => true,
            'data' => [
                'logs' => $logs,
                'pagination' => [
                    'total' => (int)$total,
                    'page' => (int)$page,
                    'pageSize' => (int)$pageSize,
                    'totalPages' => ceil($total / $pageSize)
                ]
            ]
        ]);
        
    } catch (Exception $e) {
        $this->response->throwJson([
            'success' => false,
            'message' => '获取刷新日志失败: ' . $e->getMessage()
        ]);
    }
}

/**
 * 获取最近刷新统计（用于仪表板）
 */
public function getRecentRefreshStats()
{
    try {
        $days = $this->request->get('days', 7);
        
        $db = UrlNav_Plugin::getDbConnection();
        
        // 1. 获取最近N天的刷新统计
        $dailyStatsSql = "
            SELECT 
                DATE(last_refresh) as refresh_date,
                COUNT(*) as total_refreshes,
                SUM(CASE WHEN last_error IS NOT NULL AND last_error != '' THEN 1 ELSE 0 END) as failed_refreshes,
                SUM(CASE WHEN last_error IS NULL OR last_error = '' THEN 1 ELSE 0 END) as success_refreshes
            FROM urlnav_urls 
            WHERE rss_url IS NOT NULL 
            AND rss_url != ''
            AND last_refresh IS NOT NULL
            AND last_refresh >= DATE('now', '-' || ? || ' days')
            GROUP BY DATE(last_refresh)
            ORDER BY refresh_date DESC
        ";
        
        $stmt = $db->prepare($dailyStatsSql);
        $stmt->execute([$days]);
        $dailyStats = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        // 2. 获取成功/失败总数
        $totalStatsSql = "
            SELECT 
                COUNT(*) as total_urls,
                SUM(CASE WHEN last_error IS NOT NULL AND last_error != '' THEN 1 ELSE 0 END) as total_failed,
                SUM(CASE WHEN last_error IS NULL OR last_error = '' THEN 1 ELSE 0 END) as total_success,
                SUM(CASE WHEN last_error IS NOT NULL AND last_error != '' AND last_refresh >= datetime('now', '-1 day') THEN 1 ELSE 0 END) as recent_failed
            FROM urlnav_urls 
            WHERE rss_url IS NOT NULL 
            AND rss_url != ''
            AND is_active = 1
        ";
        
        $totalStmt = $db->prepare($totalStatsSql);
        $totalStmt->execute();
        $totalStats = $totalStmt->fetch(PDO::FETCH_ASSOC);
        
        // 3. 获取最常见的错误
        $commonErrorsSql = "
            SELECT 
                last_error,
                COUNT(*) as error_count
            FROM urlnav_urls 
            WHERE last_error IS NOT NULL 
            AND last_error != ''
            AND last_refresh >= datetime('now', '-7 days')
            GROUP BY last_error
            ORDER BY error_count DESC
            LIMIT 10
        ";
        
        $errorsStmt = $db->prepare($commonErrorsSql);
        $errorsStmt->execute();
        $commonErrors = $errorsStmt->fetchAll(PDO::FETCH_ASSOC);
        
        $this->response->throwJson([
            'success' => true,
            'data' => [
                'daily_stats' => $dailyStats,
                'total_stats' => $totalStats,
                'common_errors' => $commonErrors,
                'time_range' => $days . '天'
            ]
        ]);
        
    } catch (Exception $e) {
        $this->response->throwJson([
            'success' => false,
            'message' => '获取刷新统计失败: ' . $e->getMessage()
        ]);
    }
}

/**
 * 导出成功网址（修复版）
 */
public function exportSuccessUrls()
{
    try {
        $db = UrlNav_Plugin::getDbConnection();
        
        // 🔴 修复：查询最近一次刷新成功的网址
        // 方法1：根据last_error为空判断
        $stmt = $db->prepare("
            SELECT 
                u.id,
                u.url,
                u.title as site_name,
                u.rss_url,
                u.last_error,
                u.last_refresh,
                u.success_count,
                u.failure_count,
                u.star_rating,
                u.is_active,
                u.is_online,
                c.name as category_name
            FROM urlnav_urls u
            LEFT JOIN urlnav_categories c ON u.category_id = c.id
            WHERE u.rss_url IS NOT NULL
            AND u.rss_url != ''
            AND u.is_active = 1
            -- 关键：最近一次刷新没有错误，且成功次数大于失败次数
            AND (u.last_error IS NULL OR u.last_error = '')
            AND (u.success_count > u.failure_count OR u.success_count > 0)
            AND u.last_refresh IS NOT NULL
            ORDER BY u.last_refresh DESC
        ");
        $stmt->execute();
        $urls = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        // 生成CSV内容
        $csvContent = "ID,网站名称,网站地址,RSS地址,最后刷新时间(北京时间),成功次数,失败次数,成功率,星级评分,网站状态,分类\n";
        
        foreach ($urls as $url) {
            // 使用正确的北京时间转换
            $refreshTime = $this->convertToBeijingTimeCorrectly($url['last_refresh']);
            
            // 计算成功率
            $total = $url['success_count'] + $url['failure_count'];
            $successRate = $total > 0 ? round(($url['success_count'] / $total) * 100, 2) : 0;
            
            $csvContent .= sprintf(
                '"%s","%s","%s","%s","%s","%s","%s","%s%%","%s","%s","%s"' . "\n",
                $url['id'],
                $url['site_name'] ?? '',
                $url['url'] ?? '',
                $url['rss_url'] ?? '',
                $refreshTime,
                $url['success_count'] ?? 0,
                $url['failure_count'] ?? 0,
                $successRate,
                $url['star_rating'] ?? 0,
                $url['is_online'] ? '在线' : '离线',
                $url['category_name'] ?? ''
            );
        }
        
        $this->response->throwJson(array(
            'success' => true,
            'csv_data' => $csvContent,
            'count' => count($urls)
        ));
        
    } catch (Exception $e) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '导出成功网址失败: ' . $e->getMessage()
        ));
    }
}

public function exportFailedUrls()
{
    try {
        $db = UrlNav_Plugin::getDbConnection();
        
        // 🔴 直接复制 exportSuccessUrls() 的SQL结构，只改WHERE条件
        $stmt = $db->prepare("
            SELECT 
                u.id,
                u.url,
                u.title as site_name,
                u.rss_url,
                u.last_error,
                u.last_refresh,
                u.success_count,
                u.failure_count,
                u.is_active,  // 🔴 注意：失败导出没有 star_rating 字段
                u.is_online,
                c.name as category_name
            FROM urlnav_urls u
            LEFT JOIN urlnav_categories c ON u.category_id = c.id
            WHERE u.rss_url IS NOT NULL
            AND u.rss_url != ''
            AND u.is_active = 1
            -- 🔴 关键：只改这里，其他完全一样
            AND u.last_error IS NOT NULL 
            AND u.last_error != ''
            ORDER BY u.last_refresh DESC
        ");
        $stmt->execute();
        $urls = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        // 🔴 直接复制 exportSuccessUrls() 的CSV生成逻辑
        $csvContent = "ID,网站名称,网站地址,RSS地址,最后刷新时间(北京时间),错误信息,成功次数,失败次数,成功率,网站状态,分类\n";
        
        foreach ($urls as $url) {
            // 🔴 使用相同的时间转换方法
            $refreshTime = '';
            if (!empty($url['last_refresh']) && $url['last_refresh'] != '0000-00-00 00:00:00') {
                $date = new DateTime($url['last_refresh']);
                $date->setTimezone(new DateTimeZone('Asia/Shanghai'));
                $refreshTime = $date->format('Y-m-d H:i:s');
            } else {
                $refreshTime = '从未刷新';
            }
            
            // 计算成功率
            $total = $url['success_count'] + $url['failure_count'];
            $successRate = $total > 0 ? round(($url['success_count'] / $total) * 100, 2) : 0;
            
            $csvContent .= sprintf(
                '"%s","%s","%s","%s","%s","%s","%s","%s","%s%%","%s","%s"' . "\n",
                $url['id'],
                $url['site_name'] ?? '',
                $url['url'] ?? '',
                $url['rss_url'] ?? '',
                $refreshTime,
                str_replace('"', '""', $url['last_error'] ?? ''),
                $url['success_count'] ?? 0,
                $url['failure_count'] ?? 0,
                $successRate,
                $url['is_online'] ? '在线' : '离线',
                $url['category_name'] ?? ''
            );
        }
        
        $this->response->throwJson(array(
            'success' => true,
            'csv_data' => $csvContent,
            'count' => count($urls)
        ));
        
    } catch (Exception $e) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '导出失败: ' . $e->getMessage()
        ));
    }
}
/**
 * 正确的北京时间转换方法
 */
private function convertToBeijingTimeCorrectly($datetime)
{
    if (empty($datetime) || $datetime == '0000-00-00 00:00:00') {
        return '';
    }
    
    try {
        // 方法1：明确指定输入时区（如果知道数据库存储的时区）
        // 假设数据库存储的是UTC时间
        $utc = new DateTimeZone('UTC');
        $beijing = new DateTimeZone('Asia/Shanghai');
        
        // 创建DateTime对象，明确指定输入时区为UTC
        $date = DateTime::createFromFormat('Y-m-d H:i:s', $datetime, $utc);
        
        if ($date === false) {
            // 如果格式不匹配，尝试其他方法
            $date = new DateTime($datetime, $utc);
        }
        
        // 转换为北京时间
        $date->setTimezone($beijing);
        return $date->format('Y-m-d H:i:s');
        
    } catch (Exception $e) {
        // 方法2：使用你的Rss.php中的方法
        return $this->convertUsingRssMethod($datetime);
    }
}

/**
 * 复制Rss.php中的convertToBeijingTime方法
 */
private function convertUsingRssMethod($datetime)
{
    if (empty($datetime) || $datetime == '0000-00-00 00:00:00' || $datetime == '0000-00-00 00:00') {
        return '';
    }
    
    try {
        // 创建DateTime对象
        $date = new DateTime($datetime);
        
        // 如果已经是北京时间，直接返回
        if ($date->getTimezone()->getName() == 'Asia/Shanghai') {
            return $date->format('Y-m-d H:i:s');
        }
        
        // 转换为北京时间
        $date->setTimezone(new DateTimeZone('Asia/Shanghai'));
        return $date->format('Y-m-d H:i:s');
    } catch (Exception $e) {
        // 如果解析失败，尝试简单的时间转换
        $timestamp = strtotime($datetime);
        if ($timestamp !== false) {
            // 服务器时间已经是北京时间，直接返回
            return date('Y-m-d H:i:s', $timestamp);
        }
        return $datetime;
    }
}
    /**
     * 获取状态检查定时任务统计
     */
    public function getStatusCronStats()
    {
        try {
            $stats = UrlNav_Plugin::getStatusCronStats();
            
            $this->response->throwJson(array(
                'success' => true,
                'data' => $stats
            ));
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '获取状态检查定时任务统计失败: ' . $e->getMessage()
            ));
        }
    }

/**
 * 检查网站状态 - 修复版
 */
public function checkStatus()
{
    try {
        // 检查是否是批量检查
        $urlIds = $this->request->get('url_ids');
        $batchInfo = $this->request->get('batch_info');
        
        // 解析URL IDs
        $idArray = null;
        if ($urlIds && $urlIds !== '') {
            // 处理不同的ID格式
            if (is_array($urlIds)) {
                $idArray = $urlIds;
            } else if (strpos($urlIds, ',') !== false) {
                // 逗号分隔的字符串
                $idArray = array_map('trim', explode(',', $urlIds));
                $idArray = array_filter($idArray, function($id) {
                    return is_numeric($id) && $id > 0;
                });
            } else if (is_numeric($urlIds)) {
                // 单个ID
                $idArray = [$urlIds];
            }
        }
        
        // 解析批次信息
        $batchData = null;
        if ($batchInfo && is_string($batchInfo)) {
            $batchData = json_decode($batchInfo, true);
        } else if (is_array($batchInfo)) {
            $batchData = $batchInfo;
        }
        
        // 如果是选中的网址，需要特殊处理批次信息
        if (!empty($idArray) && $batchData) {
            // 重新计算批次信息，因为选中的网址总数可能和全部网址不同
            $batchSize = $batchData['size'] ?? 10;
            $totalSelected = count($idArray);
            $totalBatches = ceil($totalSelected / $batchSize);
            $batchNumber = $batchData['batch'] ?? 1;
            
            // 确保批次号不超过总批次
            if ($batchNumber > $totalBatches) {
                return $this->response->throwJson([
                    'success' => true,
                    'message' => '所有选中的网址已检查完成',
                    'total' => 0,
                    'success_count' => 0,
                    'failed_count' => 0,
                    'has_more' => false
                ]);
            }
            
            // 获取当前批次要检查的ID
            $offset = ($batchNumber - 1) * $batchSize;
            $batchIds = array_slice($idArray, $offset, $batchSize);
            
            // 调用检查函数
            $result = UrlNav_Plugin::manualCheckStatus($batchIds, true, $batchInfo);
            
            // 更新批次信息
            $result['batch_number'] = $batchNumber;
            $result['total_batches'] = $totalBatches;
            $result['batch_info'] = json_encode([
                'batch' => $batchNumber,
                'total' => $totalBatches,
                'size' => $batchSize,
                'selected_ids' => implode(',', $idArray) // 记录所有选中的ID
            ]);
            
            $this->response->throwJson($result);
            return;
        }
        
        // 如果没有选中网址，检查全部（已有的逻辑）
        $result = UrlNav_Plugin::manualCheckStatus(null, true, $batchInfo);
        $this->response->throwJson($result);
        
    } catch (Exception $e) {
        $this->response->throwJson([
            'success' => false,
            'message' => '检查失败: ' . $e->getMessage()
        ]);
    }
}
// 在 Action.php 中修复 checkSingleStatus 方法
public function checkSingleStatus()
{
    try {
        $urlId = $this->request->get('id');
        if (empty($urlId)) {
            $urlId = $this->request->get('url_id');
        }
        
        if (empty($urlId)) {
            throw new Exception('ID不能为空');
        }
        
        $result = UrlNav_Plugin::manualCheckStatus($urlId);
        
        // 修复：检查返回的数据结构
        if (isset($result['success']) && $result['success'] === true) {
            if (isset($result['results']) && is_array($result['results'])) {
                // 如果是批量检查的结果
                foreach ($result['results'] as $urlId => $checkResult) {
                    $this->response->throwJson([
                        'success' => true,
                        'message' => '检查完成',
                        'data' => $checkResult
                    ]);
                    return;
                }
            } else {
                // 如果是单次检查的结果
                $this->response->throwJson([
                    'success' => true,
                    'message' => '检查完成',
                    'data' => $result['data'] ?? $result
                ]);
                return;
            }
        } else {
            // 检查失败
            $this->response->throwJson([
                'success' => false,
                'message' => $result['message'] ?? '检查失败'
            ]);
        }
        
    } catch (Exception $e) {
        $this->response->throwJson([
            'success' => false,
            'message' => '检查失败: ' . $e->getMessage()
        ]);
    }
}

    /**
     * 获取状态统计
     */
    public function getStatusStats()
    {
        try {
            $stats = UrlNav_Plugin::getStatusStats();
            
            $this->response->throwJson([
                'success' => true,
                'data' => $stats
            ]);
        } catch (Exception $e) {
            $this->response->throwJson([
                'success' => false,
                'message' => '获取统计失败: ' . $e->getMessage()
            ]);
        }
    }

    /**
     * 添加分类 - 模仿Collection的add方法
     */
    public function addCategory()
    {
        try {
            $name = $this->request->get('name');
            $description = $this->request->get('description');
            $sort_order = $this->request->get('sort_order', 0);

            if (empty($name)) {
                throw new Exception('分类名称不能为空');
            }

            // 检查名称是否已存在 - 模仿Collection插件
            $stmt = $this->db->prepare("SELECT COUNT(*) FROM urlnav_categories WHERE name = ? AND is_active = 1");
            $stmt->execute(array($name));
            $count = $stmt->fetchColumn();
            
            if ($count > 0) {
                throw new Exception('分类名称已存在');
            }

            $stmt = $this->db->prepare("INSERT INTO urlnav_categories (name, description, sort_order) VALUES (?, ?, ?)");
            $stmt->execute(array($name, $description, $sort_order));

            $id = $this->db->lastInsertId();

            $this->response->throwJson(array(
                'success' => true,
                'message' => '分类添加成功',
                'data' => array('id' => $id)
            ));
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '添加失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 更新分类 - 模仿Collection的update方法
     */
    public function updateCategory()
    {
        try {
            $id = $this->request->get('id');
            $name = $this->request->get('name');
            $description = $this->request->get('description');
            $sort_order = $this->request->get('sort_order', 0);

            if (empty($id) || empty($name)) {
                throw new Exception('ID和分类名称不能为空');
            }

            // 检查名称是否已存在（排除自身）- 模仿Collection插件
            $stmt = $this->db->prepare("SELECT COUNT(*) FROM urlnav_categories WHERE name = ? AND id != ? AND is_active = 1");
            $stmt->execute(array($name, $id));
            $count = $stmt->fetchColumn();
            
            if ($count > 0) {
                throw new Exception('分类名称已存在');
            }

            $stmt = $this->db->prepare("UPDATE urlnav_categories SET name = ?, description = ?, sort_order = ? WHERE id = ?");
            $result = $stmt->execute(array($name, $description, $sort_order, $id));

            if ($result) {
                $this->response->throwJson(array(
                    'success' => true,
                    'message' => '分类更新成功'
                ));
            } else {
                throw new Exception('分类不存在或更新失败');
            }
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '更新失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 删除分类 - 模仿Collection的delete方法
     */
    public function deleteCategory()
    {
        try {
            $id = $this->request->get('id');

            if (empty($id)) {
                throw new Exception('ID不能为空');
            }

            // 检查分类下是否有网址
            $checkStmt = $this->db->prepare("SELECT COUNT(*) FROM urlnav_urls WHERE category_id = ? AND is_active = 1");
            $checkStmt->execute(array($id));
            $urlCount = $checkStmt->fetchColumn();
            
            if ($urlCount > 0) {
                throw new Exception('该分类下还有' . $urlCount . '个网址，无法删除');
            }

            $stmt = $this->db->prepare("UPDATE urlnav_categories SET is_active = 0 WHERE id = ?");
            $result = $stmt->execute(array($id));

            if ($result) {
                $this->response->throwJson(array(
                    'success' => true,
                    'message' => '分类删除成功'
                ));
            } else {
                throw new Exception('分类不存在或删除失败');
            }
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '删除失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 批量删除分类 - 模仿Collection的batchDelete方法
     */
    public function batchDeleteCategories()
    {
        try {
            // Collection插件处理数组的方式
            $ids = $this->request->filter('int')->getArray('category');

            if (empty($ids)) {
                $rawIds = $this->request->get('category');
                if (!empty($rawIds)) {
                    $ids = is_array($rawIds) ? $rawIds : array($rawIds);
                    $ids = array_map('intval', $ids);
                }
            }

            if (empty($ids) || !is_array($ids)) {
                throw new Exception('请选择要删除的分类');
            }

            $ids = array_filter($ids, function($id) {
                return is_numeric($id) && $id > 0;
            });

            if (empty($ids)) {
                throw new Exception('无效的分类ID');
            }

            // 检查是否有网址关联到这些分类
            $placeholders = implode(',', array_fill(0, count($ids), '?'));
            $checkStmt = $this->db->prepare("SELECT COUNT(*) FROM urlnav_urls WHERE category_id IN ($placeholders) AND is_active = 1");
            $checkStmt->execute($ids);
            $urlCount = $checkStmt->fetchColumn();
            
            if ($urlCount > 0) {
                throw new Exception('选中的分类下还有' . $urlCount . '个网址，无法删除');
            }

            $stmt = $this->db->prepare("UPDATE urlnav_categories SET is_active = 0 WHERE id IN ($placeholders)");
            $result = $stmt->execute($ids);

            if ($result) {
                $this->response->throwJson(array(
                    'success' => true,
                    'message' => '分类批量删除成功'
                ));
            } else {
                throw new Exception('删除失败');
            }
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '批量删除失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 获取单个分类 - 模仿Collection的get方法
     */
    public function getCategory()
    {
        try {
            $id = $this->request->get('id');

            if (empty($id)) {
                throw new Exception('ID不能为空');
            }

            $stmt = $this->db->prepare("SELECT * FROM urlnav_categories WHERE id = ?");
            $stmt->execute(array($id));
            $category = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($category) {
                $this->response->throwJson(array(
                    'success' => true,
                    'data' => $category
                ));
            } else {
                throw new Exception('分类不存在');
            }
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '查询失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 获取所有分类 - 模仿Collection的getAll方法
     */
    public function getAllCategories()
    {
        try {
            $stmt = $this->db->query("SELECT * FROM urlnav_categories WHERE is_active = 1 ORDER BY sort_order, created_at DESC");
            $categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            $this->response->throwJson(array(
                'success' => true,
                'data' => $categories
            ));
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '查询失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 添加网址 - 模仿Collection的add方法
     */
    public function addUrl()
    {
        try {
            $title = $this->request->get('title');
            $url = $this->request->get('url');
            $description = $this->request->get('description');
            $rss_url = $this->request->get('rss_url', '');
            $category_id = $this->request->get('category_id');
            $sort_order = $this->request->get('sort_order', 0);

            if (empty($title)) {
                throw new Exception('网站标题不能为空');
            }

            if (empty($url)) {
                throw new Exception('网站地址不能为空');
            }

            // 验证URL格式
            if (!UrlNav_Plugin::validateUrl($url)) {
                throw new Exception('网站地址格式无效，请使用http://或https://开头的完整地址');
            }

            // 如果提供了RSS地址，验证格式
            if (!empty($rss_url) && !UrlNav_Plugin::validateUrl($rss_url)) {
                throw new Exception('RSS地址格式无效，请使用http://或https://开头的完整地址');
            }

            // 检查标题是否已存在
            $stmt = $this->db->prepare("SELECT COUNT(*) FROM urlnav_urls WHERE title = ? AND is_active = 1");
            $stmt->execute(array($title));
            $count = $stmt->fetchColumn();
            
            if ($count > 0) {
                throw new Exception('网站标题已存在');
            }
            
             // 获取星级评分
        $starRating = $this->request->get('star_rating', 0);
        $starRating = intval($starRating);
        // 限制在0-3之间
        $starRating = max(0, min(3, $starRating));

            // 检查URL是否已存在
            $stmt = $this->db->prepare("SELECT COUNT(*) FROM urlnav_urls WHERE url = ? AND is_active = 1");
            $stmt->execute(array($url));
            $count = $stmt->fetchColumn();
            
            if ($count > 0) {
                throw new Exception('网站地址已存在');
            }

$stmt = $this->db->prepare("INSERT INTO urlnav_urls (title, url, description, rss_url, star_rating, category_id, sort_order) VALUES (?, ?, ?, ?, ?, ?, ?)");
$stmt->execute(array($title, $url, $description, $rss_url, $starRating, $category_id, $sort_order));

            $id = $this->db->lastInsertId();

            $this->response->throwJson(array(
                'success' => true,
                'message' => '网址添加成功',
                'data' => array('id' => $id)
            ));
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '添加失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 更新网址 - 模仿Collection的update方法
     */
   /**
 * 更新网址 - 模仿Collection的update方法
 */
public function updateUrl()
{
    try {
        $id = $this->request->get('id');
        $title = $this->request->get('title');
        $url = $this->request->get('url');
        $description = $this->request->get('description');
        $rss_url = $this->request->get('rss_url', '');
        $category_id = $this->request->get('category_id');
        $sort_order = $this->request->get('sort_order', 0);
        // 新增：获取星级评分
        $star_rating = $this->request->get('star_rating', 0);
        $star_rating = intval($star_rating);
        // 限制在0-3之间
        $star_rating = max(0, min(3, $star_rating));

        if (empty($id) || empty($title) || empty($url)) {
            throw new Exception('ID、标题和网址不能为空');
        }

        // 验证URL格式
        if (!UrlNav_Plugin::validateUrl($url)) {
            throw new Exception('网站地址格式无效，请使用http://或https://开头的完整地址');
        }

        // 如果提供了RSS地址，验证格式
        if (!empty($rss_url) && !UrlNav_Plugin::validateUrl($rss_url)) {
            throw new Exception('RSS地址格式无效，请使用http://或https://开头的完整地址');
        }

        // 检查标题是否已存在（排除自身）
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM urlnav_urls WHERE title = ? AND id != ? AND is_active = 1");
        $stmt->execute(array($title, $id));
        $count = $stmt->fetchColumn();
        
        if ($count > 0) {
            throw new Exception('网站标题已存在');
        }

        // 检查URL是否已存在（排除自身）
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM urlnav_urls WHERE url = ? AND id != ? AND is_active = 1");
        $stmt->execute(array($url, $id));
        $count = $stmt->fetchColumn();
        
        if ($count > 0) {
            throw new Exception('网站地址已存在');
        }

        // 修改这里：添加 star_rating 字段
        $stmt = $this->db->prepare("UPDATE urlnav_urls SET title = ?, url = ?, description = ?, rss_url = ?, category_id = ?, sort_order = ?, star_rating = ? WHERE id = ?");
        $result = $stmt->execute(array($title, $url, $description, $rss_url, $category_id, $sort_order, $star_rating, $id));

        if ($result) {
            $this->response->throwJson(array(
                'success' => true,
                'message' => '网址更新成功'
            ));
        } else {
            throw new Exception('网址不存在或更新失败');
        }
    } catch (Exception $e) {
        $this->response->throwJson(array(
            'success' => false,
            'message' => '更新失败: ' . $e->getMessage()
        ));
    }
}

    /**
     * 删除网址 - 模仿Collection的delete方法
     */
    public function deleteUrl()
    {
        try {
            $id = $this->request->get('id');

            if (empty($id)) {
                throw new Exception('ID不能为空');
            }

            $stmt = $this->db->prepare("UPDATE urlnav_urls SET is_active = 0 WHERE id = ?");
            $result = $stmt->execute(array($id));

            if ($result) {
                $this->response->throwJson(array(
                    'success' => true,
                    'message' => '网址删除成功'
                ));
            } else {
                throw new Exception('网址不存在或删除失败');
            }
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '删除失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 批量删除网址 - 模仿Collection的batchDelete方法
     */
    public function batchDeleteUrls()
    {
        try {
            // Collection插件处理数组的方式
            $ids = $this->request->filter('int')->getArray('url');

            if (empty($ids)) {
                $rawIds = $this->request->get('url');
                if (!empty($rawIds)) {
                    $ids = is_array($rawIds) ? $rawIds : array($rawIds);
                    $ids = array_map('intval', $ids);
                }
            }

            if (empty($ids) || !is_array($ids)) {
                throw new Exception('请选择要删除的网址');
            }

            $ids = array_filter($ids, function($id) {
                return is_numeric($id) && $id > 0;
            });

            if (empty($ids)) {
                throw new Exception('无效的网址ID');
            }

            $placeholders = implode(',', array_fill(0, count($ids), '?'));
            $stmt = $this->db->prepare("UPDATE urlnav_urls SET is_active = 0 WHERE id IN ($placeholders)");
            $result = $stmt->execute($ids);

            if ($result) {
                $this->response->throwJson(array(
                    'success' => true,
                    'message' => '网址批量删除成功'
                ));
            } else {
                throw new Exception('删除失败');
            }
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '批量删除失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 获取单个网址 - 模仿Collection的get方法
     */
    public function getUrl()
    {
        try {
            $id = $this->request->get('id');

            if (empty($id)) {
                throw new Exception('ID不能为空');
            }

            $stmt = $this->db->prepare("SELECT * FROM urlnav_urls WHERE id = ?");
            $stmt->execute(array($id));
            $url = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($url) {
                $this->response->throwJson(array(
                    'success' => true,
                    'data' => $url
                ));
            } else {
                throw new Exception('网址不存在');
            }
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '查询失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 获取所有网址 - 模仿Collection的getAll方法
     */
    public function getAllUrls()
    {
        try {
            $stmt = $this->db->query("SELECT * FROM urlnav_urls WHERE is_active = 1 ORDER BY sort_order, created_at DESC");
            $urls = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            $this->response->throwJson(array(
                'success' => true,
                'data' => $urls
            ));
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '查询失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 导出OPML格式数据
     */
    public function exportOpml()
    {
        try {
            // 获取所有分类和网址
            $categories = $this->db->query("SELECT * FROM urlnav_categories WHERE is_active = 1 ORDER BY sort_order")->fetchAll(PDO::FETCH_ASSOC);
            $urls = $this->db->query("SELECT * FROM urlnav_urls WHERE is_active = 1 AND rss_url != '' AND rss_url IS NOT NULL AND TRIM(rss_url) != '' ORDER BY sort_order")->fetchAll(PDO::FETCH_ASSOC);
            
            // 按分类组织网址
            $urlsByCategory = [];
            foreach ($urls as $url) {
                $categoryId = $url['category_id'] ? $url['category_id'] : 'uncategorized';
                if (!isset($urlsByCategory[$categoryId])) {
                    $urlsByCategory[$categoryId] = [];
                }
                $urlsByCategory[$categoryId][] = $url;
            }
            
            // 创建OPML XML
            $xml = new DOMDocument('1.0', 'UTF-8');
            $xml->formatOutput = true;
            
            $opml = $xml->createElement('opml');
            $opml->setAttribute('version', '2.0');
            $opml->setAttribute('xmlns:frss', 'https://freshrss.org/opml');
            $xml->appendChild($opml);
            
            // head部分
            $head = $xml->createElement('head');
            $opml->appendChild($head);
            
            $title = $xml->createElement('title', 'UrlNav RSS订阅');
            $head->appendChild($title);
            
            $dateCreated = $xml->createElement('dateCreated', date('r'));
            $head->appendChild($dateCreated);
            
            // body部分
            $body = $xml->createElement('body');
            $opml->appendChild($body);
            
            // 处理有分类的网址
            foreach ($categories as $category) {
                $categoryId = $category['id'];
                if (isset($urlsByCategory[$categoryId]) && !empty($urlsByCategory[$categoryId])) {
                    $outline = $xml->createElement('outline');
                    $outline->setAttribute('text', $category['name']);
                    
                    foreach ($urlsByCategory[$categoryId] as $url) {
                        $feedOutline = $xml->createElement('outline');
                        $feedOutline->setAttribute('text', $url['title']);
                        $feedOutline->setAttribute('type', 'rss');
                        $feedOutline->setAttribute('xmlUrl', $url['rss_url']);
                        $feedOutline->setAttribute('htmlUrl', $url['url']);
                        if (!empty($url['description'])) {
                            $feedOutline->setAttribute('description', $url['description']);
                        }
                        $outline->appendChild($feedOutline);
                    }
                    
                    $body->appendChild($outline);
                }
            }
            
            // 处理未分类的网址
            if (isset($urlsByCategory['uncategorized']) && !empty($urlsByCategory['uncategorized'])) {
                $outline = $xml->createElement('outline');
                $outline->setAttribute('text', '未分类');
                
                foreach ($urlsByCategory['uncategorized'] as $url) {
                    $feedOutline = $xml->createElement('outline');
                    $feedOutline->setAttribute('text', $url['title']);
                    $feedOutline->setAttribute('type', 'rss');
                    $feedOutline->setAttribute('xmlUrl', $url['rss_url']);
                    $feedOutline->setAttribute('htmlUrl', $url['url']);
                    if (!empty($url['description'])) {
                        $feedOutline->setAttribute('description', $url['description']);
                    }
                    $outline->appendChild($feedOutline);
                }
                
                $body->appendChild($outline);
            }
            
            // 设置响应头
            $filename = 'urlnav_feeds_' . date('Y-m-d') . '.opml.xml';
            $this->response->setHeader('Content-Type', 'application/xml');
            $this->response->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
            $this->response->setHeader('Cache-Control', 'no-cache, must-revalidate');
            $this->response->setHeader('Pragma', 'no-cache');
            $this->response->setHeader('Expires', '0');
            
            echo $xml->saveXML();
            
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '导出失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 导入OPML格式数据 - 修复版
     */
    public function importOpml()
    {
        try {
            // 检查是否有文件上传
            if (!isset($_FILES['opml_file']) || $_FILES['opml_file']['error'] !== UPLOAD_ERR_OK) {
                throw new Exception('请选择要上传的OPML文件，错误代码: ' . ($_FILES['opml_file']['error'] ?? '未知'));
            }
            
            $file = $_FILES['opml_file'];
            
            // 检查文件大小（限制为2MB）
            if ($file['size'] > 2 * 1024 * 1024) {
                throw new Exception('文件大小超过2MB限制');
            }
            
            if ($file['size'] == 0) {
                throw new Exception('文件为空');
            }
            
            // 读取文件内容
            $content = file_get_contents($file['tmp_name']);
            if (empty($content)) {
                throw new Exception('文件内容为空');
            }
            
            // 检查文件编码并转换为UTF-8
            $encoding = mb_detect_encoding($content, ['UTF-8', 'GBK', 'GB2312', 'BIG5', 'ASCII'], true);
            if ($encoding && $encoding != 'UTF-8') {
                $content = mb_convert_encoding($content, 'UTF-8', $encoding);
            }
            
            // 尝试移除可能的BOM头
            if (substr($content, 0, 3) == "\xEF\xBB\xBF") {
                $content = substr($content, 3);
            }
            
            // 解析XML
            libxml_use_internal_errors(true);
            $xml = simplexml_load_string($content);
            if ($xml === false) {
                $errors = libxml_get_errors();
                $errorMsg = 'XML解析失败: ';
                foreach ($errors as $error) {
                    $errorMsg .= '行 ' . $error->line . ', 列 ' . $error->column . ': ' . $error->message . '; ';
                }
                libxml_clear_errors();
                throw new Exception($errorMsg);
            }
            
            // 检查是否是有效的OPML格式
            if (!isset($xml->head) || !isset($xml->body)) {
                throw new Exception('无效的OPML格式：缺少head或body元素');
            }
            
            $importResults = [
                'total' => 0,
                'success' => 0,
                'failed' => 0,
                'categories_created' => 0,
                'urls_added' => 0,
                'urls_skipped' => 0,
                'details' => []
            ];
            
            // 开始事务
            $this->db->beginTransaction();
            
            try {
                // 获取现有分类映射
                $existingCategories = [];
                $stmt = $this->db->query("SELECT id, name FROM urlnav_categories WHERE is_active = 1");
                while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                    $existingCategories[$row['name']] = $row['id'];
                }
                
                // 获取现有网址映射
                $existingUrls = [];
                $existingRssUrls = [];
                $stmt = $this->db->query("SELECT url, rss_url, title FROM urlnav_urls WHERE is_active = 1");
                while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                    if (!empty($row['url'])) {
                        $existingUrls[$row['url']] = true;
                    }
                    if (!empty($row['rss_url'])) {
                        $existingRssUrls[$row['rss_url']] = true;
                    }
                }
                
                // 处理OPML结构 - 简化版本
                $processedCount = 0;
                
                // 遍历body下的所有outline元素
                foreach ($xml->body->children() as $outline) {
                    $processedCount++;
                    
                    // 检查是否有子元素（可能是分类）
                    $hasChildren = $outline->children()->count() > 0;
                    
                    if ($hasChildren) {
                        // 可能是分类
                        $categoryName = (string)$outline['text'];
                        if (empty($categoryName)) {
                            $categoryName = '未命名分类_' . $processedCount;
                        }
                        
                        // 处理分类
                        if (!isset($existingCategories[$categoryName])) {
                            // 创建新分类
                            $stmt = $this->db->prepare("INSERT INTO urlnav_categories (name, description, sort_order) VALUES (?, ?, ?)");
                            $stmt->execute([$categoryName, '从OPML导入', 999]);
                            $categoryId = $this->db->lastInsertId();
                            $existingCategories[$categoryName] = $categoryId;
                            $importResults['categories_created']++;
                            
                            $importResults['details'][] = [
                                'type' => 'category',
                                'name' => $categoryName,
                                'status' => 'created',
                                'message' => '分类创建成功'
                            ];
                        } else {
                            $categoryId = $existingCategories[$categoryName];
                        }
                        
                        // 处理该分类下的feed
                        foreach ($outline->children() as $feed) {
                            $importResults['total']++;
                            
                            $title = (string)$feed['text'];
                            $rssUrl = (string)$feed['xmlUrl'];
                            $htmlUrl = (string)$feed['htmlUrl'];
                            $description = isset($feed['description']) ? (string)$feed['description'] : '';
                            
                            // 如果htmlUrl为空，尝试使用link属性
                            if (empty($htmlUrl) && isset($feed['link'])) {
                                $htmlUrl = (string)$feed['link'];
                            }
                            
                            // 如果htmlUrl仍然为空，使用RSS地址作为网站地址
                            if (empty($htmlUrl) && !empty($rssUrl)) {
                                $htmlUrl = $rssUrl;
                            }
                            
                            // 验证数据
                            if (empty($title) && empty($rssUrl)) {
                                $importResults['failed']++;
                                $importResults['details'][] = [
                                    'type' => 'url',
                                    'title' => '未命名',
                                    'status' => 'failed',
                                    'message' => '标题和RSS地址都为空'
                                ];
                                continue;
                            }
                            
                            // 如果没有标题，使用RSS地址的一部分作为标题
                            if (empty($title)) {
                                $parsedUrl = parse_url($rssUrl);
                                $title = $parsedUrl['host'] ?? '未命名网站';
                            }
                            
                            // 验证URL格式
                            if (!empty($rssUrl) && !UrlNav_Plugin::validateUrl($rssUrl)) {
                                // 尝试修复URL
                                if (!preg_match('/^https?:\/\//', $rssUrl)) {
                                    $rssUrl = 'https://' . $rssUrl;
                                    if (!UrlNav_Plugin::validateUrl($rssUrl)) {
                                        $importResults['failed']++;
                                        $importResults['details'][] = [
                                            'type' => 'url',
                                            'title' => $title,
                                            'status' => 'failed',
                                            'message' => 'RSS地址格式无效: ' . $rssUrl
                                        ];
                                        continue;
                                    }
                                }
                            }
                            
                            if (!empty($htmlUrl) && !UrlNav_Plugin::validateUrl($htmlUrl)) {
                                // 尝试修复URL
                                if (!preg_match('/^https?:\/\//', $htmlUrl)) {
                                    $htmlUrl = 'https://' . $htmlUrl;
                                    if (!UrlNav_Plugin::validateUrl($htmlUrl)) {
                                        $importResults['failed']++;
                                        $importResults['details'][] = [
                                            'type' => 'url',
                                            'title' => $title,
                                            'status' => 'failed',
                                            'message' => '网站地址格式无效: ' . $htmlUrl
                                        ];
                                        continue;
                                    }
                                }
                            }
                            
                            // 检查网址是否已存在
                            $skipDuplicate = false;
                            if (!empty($htmlUrl) && isset($existingUrls[$htmlUrl])) {
                                $skipDuplicate = true;
                            }
                            
                            if (!empty($rssUrl) && isset($existingRssUrls[$rssUrl])) {
                                $skipDuplicate = true;
                            }
                            
                            // 检查标题是否已存在
                            if (!$skipDuplicate) {
                                $checkStmt = $this->db->prepare("SELECT COUNT(*) FROM urlnav_urls WHERE title = ? AND is_active = 1");
                                $checkStmt->execute([$title]);
                                if ($checkStmt->fetchColumn() > 0) {
                                    $skipDuplicate = true;
                                }
                            }
                            
                            if ($skipDuplicate) {
                                $importResults['urls_skipped']++;
                                $importResults['details'][] = [
                                    'type' => 'url',
                                    'title' => $title,
                                    'status' => 'skipped',
                                    'message' => '网址已存在'
                                ];
                                continue;
                            }
                            
                            try {
                                // 插入新网址
                                $stmt = $this->db->prepare("
                                    INSERT INTO urlnav_urls 
                                    (title, url, description, rss_url, category_id, sort_order) 
                                    VALUES (?, ?, ?, ?, ?, ?)
                                ");
                                
                                $result = $stmt->execute([
                                    $title,
                                    $htmlUrl,
                                    $description,
                                    $rssUrl,
                                    $categoryId,
                                    999
                                ]);
                                
                                if ($result) {
                                    if (!empty($htmlUrl)) {
                                        $existingUrls[$htmlUrl] = true;
                                    }
                                    if (!empty($rssUrl)) {
                                        $existingRssUrls[$rssUrl] = true;
                                    }
                                    $importResults['success']++;
                                    $importResults['urls_added']++;
                                    $importResults['details'][] = [
                                        'type' => 'url',
                                        'title' => $title,
                                        'status' => 'added',
                                        'message' => '网址添加成功'
                                    ];
                                } else {
                                    $importResults['failed']++;
                                    $importResults['details'][] = [
                                        'type' => 'url',
                                        'title' => $title,
                                        'status' => 'failed',
                                        'message' => '数据库插入失败'
                                    ];
                                }
                            } catch (Exception $e) {
                                $importResults['failed']++;
                                $importResults['details'][] = [
                                    'type' => 'url',
                                    'title' => $title,
                                    'status' => 'failed',
                                    'message' => '数据库错误: ' . $e->getMessage()
                                ];
                            }
                        }
                    } else {
                        // 可能是独立的feed
                        $importResults['total']++;
                        
                        $title = (string)$outline['text'];
                        $rssUrl = (string)$outline['xmlUrl'];
                        $htmlUrl = (string)$outline['htmlUrl'];
                        $description = isset($outline['description']) ? (string)$outline['description'] : '';
                        
                        // 验证数据
                        if (empty($title) && empty($rssUrl)) {
                            continue; // 跳过无效条目
                        }
                        
                        // 如果没有标题，使用RSS地址的一部分作为标题
                        if (empty($title)) {
                            $parsedUrl = parse_url($rssUrl);
                            $title = $parsedUrl['host'] ?? '未命名网站';
                        }
                        
                        // 使用默认分类
                        $defaultCategoryName = 'OPML导入';
                        if (!isset($existingCategories[$defaultCategoryName])) {
                            $stmt = $this->db->prepare("INSERT INTO urlnav_categories (name, description, sort_order) VALUES (?, ?, ?)");
                            $stmt->execute([$defaultCategoryName, '从OPML导入的网址', 999]);
                            $categoryId = $this->db->lastInsertId();
                            $existingCategories[$defaultCategoryName] = $categoryId;
                            $importResults['categories_created']++;
                        } else {
                            $categoryId = $existingCategories[$defaultCategoryName];
                        }
                        
                        // 检查是否已存在
                        $skipDuplicate = false;
                        if (!empty($htmlUrl) && isset($existingUrls[$htmlUrl])) {
                            $skipDuplicate = true;
                        }
                        
                        if (!empty($rssUrl) && isset($existingRssUrls[$rssUrl])) {
                            $skipDuplicate = true;
                        }
                        
                        if ($skipDuplicate) {
                            $importResults['urls_skipped']++;
                            continue;
                        }
                        
                        // 插入新网址
                        $stmt = $this->db->prepare("
                            INSERT INTO urlnav_urls 
                            (title, url, description, rss_url, category_id, sort_order) 
                            VALUES (?, ?, ?, ?, ?, ?)
                        ");
                        
                        $result = $stmt->execute([
                            $title,
                            $htmlUrl,
                            $description,
                            $rssUrl,
                            $categoryId,
                            999
                        ]);
                        
                        if ($result) {
                            if (!empty($htmlUrl)) {
                                $existingUrls[$htmlUrl] = true;
                            }
                            if (!empty($rssUrl)) {
                                $existingRssUrls[$rssUrl] = true;
                            }
                            $importResults['success']++;
                            $importResults['urls_added']++;
                            $importResults['details'][] = [
                                'type' => 'url',
                                'title' => $title,
                                'status' => 'added',
                                'message' => '网址添加成功'
                            ];
                        }
                    }
                }
                
                // 提交事务
                $this->db->commit();
                
                // 检查是否有导入数据
                if ($importResults['total'] == 0) {
                    throw new Exception('OPML文件中没有找到有效的RSS订阅数据');
                }
                
                $message = sprintf(
                    '导入完成：共处理%d个项目，成功%d个，失败%d个。创建%d个分类，添加%d个网址，跳过%d个重复项。',
                    $importResults['total'],
                    $importResults['success'],
                    $importResults['failed'],
                    $importResults['categories_created'],
                    $importResults['urls_added'],
                    $importResults['urls_skipped']
                );
                
                $this->response->throwJson(array(
                    'success' => true,
                    'message' => $message,
                    'data' => $importResults
                ));
                
            } catch (Exception $e) {
                $this->db->rollBack();
                throw $e;
            }
            
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '导入失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 获取网站信息（标题、描述、RSS地址）
     */
    public function fetchRss()
    {
        try {
            $url = $this->request->get('url');
            
            if (empty($url)) {
                throw new Exception('网址不能为空');
            }

            // 验证URL格式
            if (!UrlNav_Plugin::validateUrl($url)) {
                throw new Exception('网站地址格式无效');
            }

            // 获取网页内容
            $html = @file_get_contents($url, false, stream_context_create(array(
                'http' => array(
                    'timeout' => 10,
                    'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\r\n" .
                               "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n" .
                               "Accept-Language: zh-CN,zh;q=0.8,en;q=0.6\r\n"
                )
            )));

            if ($html === false) {
                throw new Exception('无法访问该网站');
            }

            // 检测编码并转换为UTF-8
            $encoding = mb_detect_encoding($html, array('UTF-8', 'GBK', 'GB2312', 'BIG5', 'ASCII'), true);
            if ($encoding && $encoding != 'UTF-8') {
                $html = mb_convert_encoding($html, 'UTF-8', $encoding);
            }

            // 移除BOM头
            if (substr($html, 0, 3) == "\xEF\xBB\xBF") {
                $html = substr($html, 3);
            }

            // 1. 获取网站标题
            $siteTitle = '';
            if (preg_match('/<title[^>]*>(.*?)<\/title>/is', $html, $matches)) {
                $siteTitle = trim(strip_tags($matches[1]));
                $siteTitle = preg_replace('/\s+/', ' ', $siteTitle);
                $siteTitle = html_entity_decode($siteTitle, ENT_QUOTES | ENT_HTML5, 'UTF-8');
            }

            // 2. 获取网站描述
            $siteDescription = '';
            // 尝试多种meta标签格式
            $metaPatterns = array(
                '/<meta[^>]*name=["\']description["\'][^>]*content=["\']([^"\']*)["\'][^>]*>/i',
                '/<meta[^>]*content=["\']([^"\']*)["\'][^>]*name=["\']description["\'][^>]*>/i',
                '/<meta[^>]*property=["\']og:description["\'][^>]*content=["\']([^"\']*)["\'][^>]*>/i',
                '/<meta[^>]*content=["\']([^"\']*)["\'][^>]*property=["\']og:description["\'][^>]*>/i'
            );
            
            foreach ($metaPatterns as $pattern) {
                if (preg_match($pattern, $html, $matches)) {
                    $siteDescription = trim($matches[1]);
                    $siteDescription = html_entity_decode($siteDescription, ENT_QUOTES | ENT_HTML5, 'UTF-8');
                    if (!empty($siteDescription)) {
                        break;
                    }
                }
            }

            // 3. 查找RSS链接
            $rssUrls = array();
            
            // 查找 <link> 标签中的RSS
            preg_match_all('/<link[^>]+rel=["\'](alternate|rss|rss feed|feed)["\'][^>]+href=["\']([^"\']+)["\'][^>]*>/i', $html, $matches);
            if (!empty($matches[2])) {
                foreach ($matches[2] as $rssUrl) {
                    $rssUrls[] = $rssUrl;
                }
            }
            
            // 查找 <a> 标签中的RSS
            preg_match_all('/<a[^>]+href=["\']([^"\']+\.(xml|rss|atom|rdf))["\'][^>]*>/i', $html, $matches);
            if (!empty($matches[1])) {
                foreach ($matches[1] as $rssUrl) {
                    $rssUrls[] = $rssUrl;
                }
            }

            // 查找 <link> 标签中的 feed
            preg_match_all('/<link[^>]+type=["\'](application\/rss\+xml|application\/atom\+xml|application\/rdf\+xml)["\'][^>]+href=["\']([^"\']+)["\'][^>]*>/i', $html, $matches);
            if (!empty($matches[2])) {
                foreach ($matches[2] as $rssUrl) {
                    $rssUrls[] = $rssUrl;
                }
            }

            // 去重并转换相对路径为绝对路径
            $rssUrls = array_unique($rssUrls);
            $absoluteRssUrls = array();
            $baseUrl = parse_url($url, PHP_URL_SCHEME) . '://' . parse_url($url, PHP_URL_HOST);
            
            foreach ($rssUrls as $rssUrl) {
                if (strpos($rssUrl, 'http') === 0) {
                    $absoluteRssUrls[] = $rssUrl;
                } else if (strpos($rssUrl, '/') === 0) {
                    $absoluteRssUrls[] = $baseUrl . $rssUrl;
                } else {
                    $absoluteRssUrls[] = $baseUrl . '/' . $rssUrl;
                }
            }

            // 准备返回结果
            $result = array(
                'success' => true,
                'siteInfo' => array(
                    'title' => $siteTitle,
                    'description' => $siteDescription,
                    'url' => $url
                )
            );

            if (empty($absoluteRssUrls)) {
                $result['hasRss'] = false;
                $result['message'] = '成功获取网站信息，但未找到RSS地址';
            } else {
                $result['hasRss'] = true;
                $result['rssUrls'] = $absoluteRssUrls;
                $result['message'] = '成功获取网站信息，找到 ' . count($absoluteRssUrls) . ' 个RSS地址';
            }

            $this->response->throwJson($result);
            
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '获取网站信息失败: ' . $e->getMessage()
            ));
        }
    }

    /**
     * 获取所有RSS信息并保存到缓存
     */
    public function getRssFeeds()
    {
        try {
            $result = UrlNav_Plugin::manualRefreshRss();
            
            if ($result['success']) {
                $this->response->throwJson(array(
                    'success' => true,
                    'total' => $result['totalFeeds'] ?? 0,
                    'successCount' => $result['successCount'] ?? 0,
                    'newArticles' => $result['newArticles'] ?? 0,
                    'urlCount' => $result['urlCount'] ?? 0,
                    'message' => $result['message']
                ));
            } else {
                $this->response->throwJson(array(
                    'success' => false,
                    'message' => $result['message']
                ));
            }
        } catch (Exception $e) {
            $this->response->throwJson(array(
                'success' => false,
                'message' => '获取RSS信息失败: ' . $e->getMessage()
            ));
        }
    }
}
?>