<?php

require_once __DIR__ . '/scheduled_publisher.php';
require_once __DIR__ . '/content_quality.php';
require_once __DIR__ . '/media_library.php';
require_once __DIR__ . '/database_backup.php';

function cmsEnsureTaskCenterSchema($db)
{
    return true;
}

function cmsTaskDefinitions()
{
    return [
        'scheduled_publish' => ['name'=>'定时发布','description'=>'发布已审核且到期的文章','icon'=>'fa-clock-o','permission'=>'article.publish'],
        'database_backup' => ['name'=>'数据库备份','description'=>'生成带完整性清单的数据库快照','icon'=>'fa-database','permission'=>'database'],
        'content_quality' => ['name'=>'内容质量扫描','description'=>'检查 SEO、正文、封面和站内失效链接','icon'=>'fa-check-square-o','permission'=>'content_quality'],
        'media_scan' => ['name'=>'媒体资源扫描','description'=>'统计资源类型、引用和未使用文件','icon'=>'fa-picture-o','permission'=>'media'],
    ];
}

function cmsTaskCanRun(array $definition, array $access)
{
    $permission = $definition['permission'];
    if ($permission === 'article.publish') {
        require_once __DIR__ . '/article_review.php';
        return cmsCanPublishArticles($access);
    }
    return function_exists('cmsAdminCan') && cmsAdminCan($access, $permission, 'manage');
}

function cmsExecuteTask($db, $taskKey, $rootPath)
{
    if ($taskKey === 'scheduled_publish') {
        $ids = cmsPublishScheduledArticles($db, time(), 500);
        return ['summary'=>'已发布 '.count($ids).' 篇到期文章','published_ids'=>$ids];
    }
    if ($taskKey === 'database_backup') {
        $result = cmsCreateDatabaseSnapshot($db, cmsBackupDirectory($rootPath), 'task_center');
        if (empty($result['success'])) { throw new RuntimeException($result['message'] ?? '数据库备份失败'); }
        $config=$db->fetch("SELECT config_value FROM {$db->table('config')} WHERE config_key='auto_backup_max_count'");$keep=max(1,min(100,intval($config['config_value']??10)));$deleted=cmsCleanupTaskCenterBackups(cmsBackupDirectory($rootPath),$keep);
        return ['summary'=>'备份已生成：'.$result['filename'],'filename'=>$result['filename'],'size'=>intval($result['size']),'retention'=>$keep,'deleted'=>$deleted];
    }
    if ($taskKey === 'content_quality') {
        $summary = cmsQualitySummary(cmsCollectContentQuality($db, $rootPath));
        return ['summary'=>'发现 '.$summary['contents'].' 项待优化内容，共 '.$summary['issues'].' 个问题'] + $summary;
    }
    if ($taskKey === 'media_scan') {
        $files = cmsScanMediaFiles($rootPath); $references = cmsCollectMediaReferences($db, $rootPath);
        $used = 0; $bytes = 0; $types = [];
        foreach ($files as $url=>$file) { $bytes += intval($file['size']); $types[$file['type']] = intval($types[$file['type']] ?? 0) + 1; if (!empty($references[$url])) { $used++; } }
        return ['summary'=>'扫描 '.count($files).' 个资源，使用中 '.$used.'，未使用 '.(count($files)-$used),'files'=>count($files),'used'=>$used,'unused'=>count($files)-$used,'bytes'=>$bytes,'types'=>$types];
    }
    throw new InvalidArgumentException('未知任务');
}

function cmsRunTask($db, $taskKey, $rootPath, array $actor = [], $source = 'manual')
{
    cmsEnsureTaskCenterSchema($db);
    if (!isset(cmsTaskDefinitions()[$taskKey])) { return ['success'=>false,'busy'=>false,'message'=>'任务不存在']; }
    $lockName = 'enterprise_cms_task_' . $taskKey;
    $lock = $db->fetch('SELECT GET_LOCK(?, 0) AS acquired', [$lockName]);
    if (intval($lock['acquired'] ?? 0) !== 1) { return ['success'=>false,'busy'=>true,'message'=>'任务正在运行，请稍后再试']; }
    $started = time(); $startClock = microtime(true); $runId = 0;
    try {
        $actorName = (string)($actor['name'] ?? '');
        $actorName = function_exists('mb_substr') ? mb_substr($actorName,0,50,'UTF-8') : substr($actorName,0,50);
        $runId = intval($db->insert('task_run', ['task_key'=>$taskKey,'status'=>'running','trigger_source'=>$source,'admin_id'=>intval($actor['id'] ?? 0),'admin_name'=>$actorName,'started_at'=>$started,'finished_at'=>0,'duration_ms'=>0,'summary'=>'','result_json'=>'','error_message'=>'']));
        $result = cmsExecuteTask($db, $taskKey, $rootPath);
        $duration = intval(round((microtime(true)-$startClock)*1000));
        $db->update('task_run', ['status'=>'success','finished_at'=>time(),'duration_ms'=>$duration,'summary'=>substr((string)$result['summary'],0,500),'result_json'=>json_encode($result,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),'error_message'=>''], 'id=?', [$runId]);
        return ['success'=>true,'busy'=>false,'message'=>$result['summary'],'run_id'=>$runId,'duration_ms'=>$duration,'result'=>$result];
    } catch (Throwable $e) {
        $duration = intval(round((microtime(true)-$startClock)*1000));
        if ($runId) { $db->update('task_run', ['status'=>'error','finished_at'=>time(),'duration_ms'=>$duration,'summary'=>'任务执行失败','error_message'=>substr($e->getMessage(),0,1000)], 'id=?', [$runId]); }
        error_log('EnterpriseCMS task failed ['.$taskKey.']: '.$e->getMessage());
        return ['success'=>false,'busy'=>false,'message'=>'任务执行失败：'.$e->getMessage(),'run_id'=>$runId,'duration_ms'=>$duration];
    } finally {
        $db->query('SELECT RELEASE_LOCK(?)', [$lockName]);
    }
}

function cmsTaskRecentRuns($db, $limit = 50, $taskKey = '', $status = '')
{
    cmsEnsureTaskCenterSchema($db); $where = []; $params = [];
    if (isset(cmsTaskDefinitions()[$taskKey])) { $where[]='task_key=?'; $params[]=$taskKey; }
    if (in_array($status,['running','success','error'],true)) { $where[]='status=?'; $params[]=$status; }
    $sql = 'SELECT * FROM '.$db->table('task_run').($where?' WHERE '.implode(' AND ',$where):'').' ORDER BY id DESC LIMIT '.max(1,min(200,intval($limit)));
    return $db->fetchAll($sql,$params);
}

function cmsTaskLatestByKey(array $runs)
{
    $latest=[]; foreach($runs as $run){if(!isset($latest[$run['task_key']]))$latest[$run['task_key']]=$run;} return $latest;
}

function cmsTaskRunCount($db, $taskKey = '', $status = '')
{
    cmsEnsureTaskCenterSchema($db);$where=[];$params=[];
    if(isset(cmsTaskDefinitions()[$taskKey])){$where[]='task_key=?';$params[]=$taskKey;}
    if(in_array($status,['running','success','error'],true)){$where[]='status=?';$params[]=$status;}
    $row=$db->fetch('SELECT COUNT(*) cnt FROM '.$db->table('task_run').($where?' WHERE '.implode(' AND ',$where):''),$params);return intval($row['cnt']??0);
}

function cmsTaskRunsPage($db, $page, $pageSize, $taskKey = '', $status = '')
{
    cmsEnsureTaskCenterSchema($db);$page=max(1,intval($page));$pageSize=max(10,min(100,intval($pageSize)));$where=[];$params=[];
    if(isset(cmsTaskDefinitions()[$taskKey])){$where[]='task_key=?';$params[]=$taskKey;}
    if(in_array($status,['running','success','error'],true)){$where[]='status=?';$params[]=$status;}
    return$db->fetchAll('SELECT * FROM '.$db->table('task_run').($where?' WHERE '.implode(' AND ',$where):'').' ORDER BY id DESC LIMIT '.$pageSize.' OFFSET '.(($page-1)*$pageSize),$params);
}

function cmsTaskRunDetail($db, $id)
{
    cmsEnsureTaskCenterSchema($db);return$db->fetch('SELECT * FROM '.$db->table('task_run').' WHERE id=? LIMIT 1',[intval($id)]);
}

function cmsTaskStats($db, $days = 30)
{
    cmsEnsureTaskCenterSchema($db);$days=max(1,min(365,intval($days)));$row=$db->fetch("SELECT COUNT(*) total,SUM(status='success') successes,SUM(status='error') errors,AVG(CASE WHEN status IN ('success','error') THEN duration_ms END) avg_ms FROM {$db->table('task_run')} WHERE started_at>=?",[time()-$days*86400]);$total=intval($row['total']??0);$success=intval($row['successes']??0);return['total'=>$total,'success'=>$success,'error'=>intval($row['errors']??0),'success_rate'=>$total?round($success*100/$total,1):0,'avg_ms'=>intval(round($row['avg_ms']??0))];
}

function cmsCleanupTaskRuns($db, $keepDays = 90, $keepMinimum = 200)
{
    cmsEnsureTaskCenterSchema($db);$keepDays=max(30,min(365,intval($keepDays)));$keepMinimum=max(100,min(5000,intval($keepMinimum)));
    $threshold=$db->fetch('SELECT id FROM '.$db->table('task_run').' ORDER BY id DESC LIMIT 1 OFFSET '.($keepMinimum-1));if(!$threshold)return 0;
    return$db->delete('task_run','id < ? AND status <> ? AND finished_at > 0 AND finished_at < ?',[intval($threshold['id']),'running',time()-$keepDays*86400]);
}
