<?php

require_once __DIR__ . '/system_health.php';
require_once __DIR__ . '/audit_log.php';
require_once __DIR__ . '/redirect_manager.php';

function cmsEnsureNotificationSchema($db)
{
    return true;
}

function cmsNotificationItem($key,$severity,$source,$title,$description,$url,$state)
{
    $severity=in_array($severity,['high','medium','low'],true)?$severity:'low';
    return ['key'=>$key,'severity'=>$severity,'source'=>$source,'title'=>$title,'description'=>$description,'url'=>$url,'fingerprint'=>hash('sha256',$key.'|'.json_encode($state,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)),'created_at'=>intval($state['time']??time())];
}

function cmsCollectAdminNotifications($db,$rootPath)
{
    cmsEnsureNotificationSchema($db);cmsEnsureRedirectSchema($db);$items=[];$now=time();
    try{$row=$db->fetch("SELECT COUNT(*) cnt,MAX(submitted_at) last_time FROM {$db->table('article')} WHERE deleted_at=0 AND review_status='pending'");$count=intval($row['cnt']??0);if($count>0)$items[]=cmsNotificationItem('article_review_pending','medium','内容审核','有 '.$count.' 篇文章待审核','请及时审核，避免内容发布积压。','?act=article&state=pending',['count'=>$count,'time'=>intval($row['last_time']??$now)]);}catch(Throwable $e){}
    $scheduler=cmsReadSchedulerStatus($now);if($scheduler['status']!=='ok'){$items[]=cmsNotificationItem('scheduler_'.$scheduler['status'],$scheduler['status']==='error'?'high':'medium','系统任务',$scheduler['status']==='error'?'定时发布任务执行失败':'定时发布任务长时间未运行',(string)($scheduler['message']??'请检查任务运行状态。'),'?act=system_status',['status'=>$scheduler['status'],'time'=>intval($scheduler['run_at']??0)]);}
    try{$row=$db->fetch("SELECT id,task_key,error_message,finished_at FROM {$db->table('task_run')} WHERE status='error' AND finished_at>=? ORDER BY id DESC LIMIT 1",[$now-86400]);if($row)$items[]=cmsNotificationItem('task_run_failed','high','后台任务','最近有后台任务执行失败',(string)($row['error_message']?:$row['task_key']),'?act=task_center&status=error',['id'=>intval($row['id']),'time'=>intval($row['finished_at'])]);}catch(Throwable $e){}
    try{$row=$db->fetch("SELECT COUNT(*) cnt,MAX(last_seen_at) last_time,MAX(hit_count) max_hits FROM {$db->table('not_found_log')} WHERE hit_count>=5");$count=intval($row['cnt']??0);if($count>0)$items[]=cmsNotificationItem('frequent_404','medium','访问异常',$count.' 个路径出现高频 404','单个路径最高访问 '.intval($row['max_hits']??0).' 次，请评估是否需要建立跳转。','?act=redirect',['count'=>$count,'max'=>intval($row['max_hits']??0),'time'=>intval($row['last_time']??0)]);}catch(Throwable $e){}
    try{$rows=$db->fetchAll("SELECT id,action,module,content,create_time FROM {$db->table('log')} WHERE create_time>=? ORDER BY id DESC LIMIT 500",[$now-86400]);$high=array_values(array_filter($rows,function($row){return cmsAuditClassify($row['action'],$row['module'],$row['content'])['risk']==='high';}));if($high){$items[]=cmsNotificationItem('high_risk_audit','high','安全审计','最近 24 小时有 '.count($high).' 条高风险操作','最近事件：'.($high[0]['action']??'高风险操作').' · '.($high[0]['module']??'未分类'),'?act=log&risk=high',['count'=>count($high),'id'=>intval($high[0]['id']??0),'time'=>intval($high[0]['create_time']??0)]);}}catch(Throwable $e){}
    $checks=cmsCollectSystemHealth($db,$rootPath);$bad=array_values(array_filter($checks,function($check){return($check['status']??'ok')!=='ok';}));if($bad){$errors=count(array_filter($bad,function($check){return$check['status']==='error';}));$items[]=cmsNotificationItem('system_health',$errors?'high':'medium','系统状态',$errors?$errors.' 项系统检查异常':count($bad).' 项系统检查需要关注',implode('、',array_slice(array_column($bad,'name'),0,3)),'?act=system_status',['bad'=>array_map(function($c){return[$c['name'],$c['status'],$c['value']];},$bad)]);}
    try{$mode=function_exists('getSiteConfig')?trim((string)getSiteConfig('update_remind','modal')):'modal';if($mode==='backend'&&class_exists('\\Core\\Lib\\License')){$remote=cmsFetchRemoteUpdateInfo(2);$latest=trim((string)($remote['latest_version']??''));$current=(string)\Core\Lib\License::VERSION;if($latest!==''&&cmsVersionCompare($latest,$current)>0){$description='当前版本 v'.$current.'，发现新版本 v'.$latest.'。';$change=trim((string)($remote['changelog']??''));if($change!==''){$lines=preg_split('/\r\n|\r|\n/',$change);$firstLine=trim((string)($lines[0]??''));if($firstLine!=='')$description.=' '.$firstLine;}$items[]=cmsNotificationItem('system_update_available','medium','版本更新','发现新版本 v'.$latest,$description,'?act=version',['latest'=>$latest,'time'=>$now]);}}}catch(Throwable $e){}
    usort($items,function($a,$b){$rank=['high'=>3,'medium'=>2,'low'=>1];return($rank[$b['severity']]<=>$rank[$a['severity']])?:($b['created_at']<=>$a['created_at']);});return$items;
}

function cmsApplyNotificationReadState($db,$adminId,array $items)
{
    cmsEnsureNotificationSchema($db);$rows=$db->fetchAll("SELECT notification_key,fingerprint,read_at FROM {$db->table('notification_read')} WHERE admin_id=?",[intval($adminId)]);$read=[];foreach($rows as$row)$read[$row['notification_key']]=$row;
    foreach($items as&$item){$row=$read[$item['key']]??null;$item['read']=$row&&hash_equals((string)$row['fingerprint'],(string)$item['fingerprint']);$item['read_at']=$item['read']?intval($row['read_at']):0;}unset($item);return$items;
}

function cmsMarkNotificationRead($db,$adminId,$key,$fingerprint)
{
    if(!preg_match('/^[a-z0-9_\-]{1,100}$/i',(string)$key)||!preg_match('/^[a-f0-9]{64}$/',(string)$fingerprint))return false;cmsEnsureNotificationSchema($db);
    $existing=$db->fetch("SELECT id FROM {$db->table('notification_read')} WHERE admin_id=? AND notification_key=?",[intval($adminId),$key]);$data=['fingerprint'=>$fingerprint,'read_at'=>time()];if($existing)$db->update('notification_read',$data,'id=?',[$existing['id']]);else{$data['admin_id']=intval($adminId);$data['notification_key']=$key;$db->insert('notification_read',$data);}return true;
}

function cmsUnreadNotificationCount(array $items){return count(array_filter($items,function($item){return empty($item['read']);}));}

function cmsFilterNotificationsByAccess(array $items,array $access)
{
    if(!function_exists('cmsAdminCan'))return$items;
    return array_values(array_filter($items,function($item)use($access){parse_str((string)(parse_url($item['url']??'',PHP_URL_QUERY)?:''),$query);$act=trim((string)($query['act']??''));return$act===''||cmsAdminCan($access,$act,'view');}));
}
