<?php

function cmsImportFieldDefinitions($type)
{
    $common=['channel'=>['label'=>'栏目ID或名称','required'=>true],'title'=>['label'=>'标题','required'=>true],'summary'=>['label'=>'摘要','required'=>false],'content'=>['label'=>'正文HTML','required'=>false],'litpic'=>['label'=>'封面地址','required'=>false],'tags'=>['label'=>'标签','required'=>false],'seo_title'=>['label'=>'SEO标题','required'=>false],'seo_keywords'=>['label'=>'SEO关键词','required'=>false],'seo_description'=>['label'=>'SEO描述','required'=>false],'status'=>['label'=>'状态(draft/publish)','required'=>false]];
    if($type==='product'){$common['product_code']=['label'=>'产品编号','required'=>false];$common['price']=['label'=>'价格','required'=>false];$common['market_price']=['label'=>'市场价','required'=>false];$common['stock']=['label'=>'库存','required'=>false];}
    return $common;
}

function cmsImportNormalizeHeader($value)
{
    $value=trim(preg_replace('/^\xEF\xBB\xBF/','',(string)$value));$aliases=['栏目'=>'channel','栏目ID'=>'channel','栏目名称'=>'channel','标题'=>'title','文章标题'=>'title','产品标题'=>'title','摘要'=>'summary','正文'=>'content','内容'=>'content','封面'=>'litpic','封面图'=>'litpic','标签'=>'tags','SEO标题'=>'seo_title','SEO关键词'=>'seo_keywords','SEO描述'=>'seo_description','状态'=>'status','产品编号'=>'product_code','价格'=>'price','市场价'=>'market_price','库存'=>'stock'];return$aliases[$value]??strtolower(preg_replace('/[^a-z0-9_]/i','',$value));
}

function cmsImportReadCsv($path,$maxRows=1000)
{
    $raw=file_get_contents($path);if($raw===false)return['success'=>false,'message'=>'无法读取 CSV 文件'];
    $encoding=function_exists('mb_detect_encoding')?mb_detect_encoding($raw,['UTF-8','GB18030','GBK','BIG5'],true):'UTF-8';if($encoding&&$encoding!=='UTF-8')$raw=mb_convert_encoding($raw,'UTF-8',$encoding);
    $handle=fopen('php://temp','w+');fwrite($handle,$raw);rewind($handle);$rows=[];while(($row=fgetcsv($handle))!==false){if(count($rows)>=$maxRows+1){fclose($handle);return['success'=>false,'message'=>'数据超过 '.$maxRows.' 行限制'];}$rows[]=$row;}fclose($handle);return cmsImportTabularResult($rows);
}

function cmsImportColumnIndex($reference)
{
    preg_match('/^[A-Z]+/i',(string)$reference,$m);$letters=strtoupper($m[0]??'A');$index=0;for($i=0;$i<strlen($letters);$i++)$index=$index*26+(ord($letters[$i])-64);return max(0,$index-1);
}

function cmsImportReadXlsx($path,$maxRows=1000)
{
    if(!class_exists('ZipArchive'))return['success'=>false,'message'=>'服务器未启用 ZIP 扩展'];$zip=new ZipArchive();if($zip->open($path)!==true)return['success'=>false,'message'=>'Excel 文件无法打开'];
    $shared=[];$sharedXml=$zip->getFromName('xl/sharedStrings.xml');if($sharedXml!==false){if(strlen($sharedXml)>10*1024*1024){$zip->close();return['success'=>false,'message'=>'Excel 共享文本过大'];}$xml=@simplexml_load_string($sharedXml);if($xml)foreach($xml->si as$si){$parts=[];if(isset($si->t))$parts[]=(string)$si->t;foreach($si->r as$run)$parts[]=(string)$run->t;$shared[]=implode('',$parts);}}
    $sheet=$zip->getFromName('xl/worksheets/sheet1.xml');$zip->close();if($sheet===false||strlen($sheet)>20*1024*1024)return['success'=>false,'message'=>'Excel 第一个工作表不存在或过大'];$xml=@simplexml_load_string($sheet);if(!$xml)return['success'=>false,'message'=>'Excel 工作表格式错误'];$xml->registerXPathNamespace('x','http://schemas.openxmlformats.org/spreadsheetml/2006/main');$rows=[];
    foreach($xml->xpath('//x:sheetData/x:row') as$rowNode){if(count($rows)>=$maxRows+1)return['success'=>false,'message'=>'数据超过 '.$maxRows.' 行限制'];$row=[];foreach($rowNode->c as$cell){$index=cmsImportColumnIndex((string)$cell['r']);$type=(string)$cell['t'];$value='';if($type==='inlineStr')$value=(string)$cell->is->t;else{$raw=(string)$cell->v;$value=$type==='s'?($shared[intval($raw)]??''):$raw;}$row[$index]=$value;}if($row){ksort($row);$max=max(array_keys($row));$rows[]=array_replace(array_fill(0,$max+1,''),$row);}}
    return cmsImportTabularResult($rows);
}

function cmsImportTabularResult(array $rows)
{
    while($rows&&count(array_filter(array_map('trim',$rows[0])))===0)array_shift($rows);if(count($rows)<2)return['success'=>false,'message'=>'文件至少需要表头和一行数据'];$headers=array_map('trim',array_shift($rows));$width=count($headers);$data=[];foreach($rows as$row){$row=array_pad($row,$width,'');$row=array_slice($row,0,$width);if(count(array_filter(array_map('trim',$row)))===0)continue;$data[]=$row;}return['success'=>true,'headers'=>$headers,'rows'=>$data];
}

function cmsImportReadFile($path,$extension,$maxRows=1000)
{
    $extension=strtolower((string)$extension);if($extension==='csv')return cmsImportReadCsv($path,$maxRows);if($extension==='xlsx')return cmsImportReadXlsx($path,$maxRows);return['success'=>false,'message'=>'仅支持 CSV 和 XLSX 文件'];
}

function cmsImportAutoMapping(array $headers,$type)
{
    $allowed=array_keys(cmsImportFieldDefinitions($type));$mapping=[];foreach($headers as$index=>$header){$field=cmsImportNormalizeHeader($header);$mapping[$index]=in_array($field,$allowed,true)?$field:'';}return$mapping;
}

function cmsImportResolveChannel($db,$value,$channelType)
{
    $value=trim((string)$value);if($value==='')return 0;if(ctype_digit($value))$row=$db->fetch("SELECT id FROM {$db->table('channel')} WHERE id=? AND channel_type=? LIMIT 1",[intval($value),$channelType]);else$row=$db->fetch("SELECT id FROM {$db->table('channel')} WHERE channel_name=? AND channel_type=? ORDER BY id ASC LIMIT 1",[$value,$channelType]);return intval($row['id']??0);
}

function cmsImportPreview($db,$type,array $headers,array $rows,array $mapping,$canPublish=false)
{
    $definitions=cmsImportFieldDefinitions($type);$used=array_values(array_filter($mapping));$errors=[];foreach($definitions as$field=>$def)if($def['required']&&!in_array($field,$used,true))$errors[]='必填字段未映射：'.$def['label'];foreach(array_count_values($used)as$field=>$count)if($count>1)$errors[]='字段重复映射：'.($definitions[$field]['label']??$field);$preview=[];$seen=[];
    foreach($rows as$offset=>$row){$line=$offset+2;$data=[];foreach($mapping as$index=>$field)if($field!==''&&isset($definitions[$field]))$data[$field]=trim((string)($row[$index]??''));$rowErrors=[];$rowWarnings=[];$title=trim((string)($data['title']??''));if($title==='')$rowErrors[]='标题不能为空';$channelId=cmsImportResolveChannel($db,$data['channel']??'',$type==='article'?1:2);if($channelId<=0)$rowErrors[]='栏目不存在或类型不匹配';if($title!==''&&isset($seen[$title]))$rowWarnings[]='文件内标题重复';$seen[$title]=true;$status=strtolower((string)($data['status']??'draft'));if(!in_array($status,['draft','publish'],true))$rowErrors[]='状态只能是 draft 或 publish';if($status==='publish'&&!$canPublish){$status='draft';$rowWarnings[]='当前角色无发布权限，已改为草稿';}foreach(['price','market_price'] as$field)if(isset($data[$field])&&$data[$field]!==''&&!is_numeric($data[$field]))$rowErrors[]=$definitions[$field]['label'].'必须是数字';if(isset($data['stock'])&&$data['stock']!==''&&!preg_match('/^-?\d+$/',$data['stock']))$rowErrors[]='库存必须是整数';$data['channel_id']=$channelId;$data['status']=$status;$preview[]=['line'=>$line,'data'=>$data,'errors'=>$rowErrors,'warnings'=>$rowWarnings];}
    return['success'=>!$errors&&!array_filter($preview,function($row){return!empty($row['errors']);}),'global_errors'=>$errors,'rows'=>$preview,'total'=>count($preview),'error_count'=>count(array_filter($preview,function($row){return!empty($row['errors']);})),'warning_count'=>array_sum(array_map(function($row){return count($row['warnings']);},$preview))];
}

function cmsImportBuildRecord($type,array $data,$adminId=0)
{
    $now=time();$base=['channel_id'=>intval($data['channel_id']),'title'=>trim((string)$data['title']),'litpic'=>trim((string)($data['litpic']??'')),'tags'=>trim((string)($data['tags']??'')),'summary'=>trim((string)($data['summary']??'')),'content'=>(string)($data['content']??''),'seo_title'=>trim((string)($data['seo_title']??'')),'seo_keywords'=>trim((string)($data['seo_keywords']??'')),'seo_description'=>trim((string)($data['seo_description']??'')),'status'=>$data['status']==='publish'?1:0,'sort_order'=>100,'create_time'=>$now,'update_time'=>$now];
    if($type==='article')return array_merge($base,['short_title'=>'','flag'=>'','source'=>'批量导入','author'=>'','external_url'=>'','click'=>0,'is_paid'=>0,'comment_enabled'=>1,'view_group_ids'=>'','download_group_ids'=>'','attachment_url'=>'','attachment_name'=>'','release_time'=>$now,'scheduled_publish_at'=>0,'published_at'=>$base['status']?$now:0,'published_by'=>$base['status']?intval($adminId):0,'review_status'=>$base['status']?'approved':'draft','submitted_by'=>0,'submitted_at'=>0,'reviewed_by'=>$base['status']?intval($adminId):0,'reviewed_at'=>$base['status']?$now:0,'review_note'=>'','deleted_at'=>0]);
    return array_merge($base,['product_code'=>trim((string)($data['product_code']??'')),'price'=>floatval($data['price']??0),'market_price'=>floatval($data['market_price']??0),'cost_price'=>0,'stock'=>intval($data['stock']??999),'pictures'=>'','flag'=>'','external_url'=>'','click'=>0,'sales'=>0,'specs'=>'','attrs'=>'','deleted_at'=>0]);
}

function cmsExecuteImport($db,$type,array $preview,$adminId=0)
{
    if(empty($preview['success']))return['success'=>false,'message'=>'预检未通过，不能导入','count'=>0];$pdo=$db->getPdo();$pdo->beginTransaction();try{$count=0;foreach($preview['rows'] as$row){$db->insert($type,cmsImportBuildRecord($type,$row['data'],$adminId));$count++;}$pdo->commit();return['success'=>true,'message'=>'成功导入 '.$count.' 条数据','count'=>$count];}catch(Throwable$e){if($pdo->inTransaction())$pdo->rollBack();error_log('EnterpriseCMS import failed: '.$e->getMessage());return['success'=>false,'message'=>'导入失败，全部数据已回滚','count'=>0];}
}

function cmsImportTemplateRows($type)
{
    $headers=array_keys(cmsImportFieldDefinitions($type));$sample=$type==='article'?['新闻中心','示例文章','文章摘要','<p>正文内容</p>','/uploads/example.jpg','企业,建站','示例文章SEO标题','企业建站,官网','示例SEO描述','draft']:['产品中心','示例产品','产品摘要','<p>产品详情</p>','/uploads/example.jpg','产品,展示','示例产品SEO标题','产品展示,企业','示例SEO描述','draft','P001','99.00','129.00','100'];return[$headers,$sample];
}

function cmsImportXlsxColumnName($index)
{
    $name='';$index=intval($index)+1;while($index>0){$index--;$name=chr(65+($index%26)).$name;$index=intdiv($index,26);}return$name;
}

function cmsCreateImportTemplateXlsx($type,$path)
{
    if(!class_exists('ZipArchive'))return false;[$headers,$sample]=cmsImportTemplateRows($type);$rows=[$headers,$sample];$sheetRows=[];foreach($rows as$rIndex=>$row){$cells=[];foreach($row as$cIndex=>$value){$ref=cmsImportXlsxColumnName($cIndex).($rIndex+1);$cells[]='<c r="'.$ref.'" t="inlineStr"><is><t xml:space="preserve">'.htmlspecialchars((string)$value,ENT_XML1|ENT_QUOTES,'UTF-8').'</t></is></c>';}$sheetRows[]='<row r="'.($rIndex+1).'">'.implode('',$cells).'</row>';}
    $files=['[Content_Types].xml'=>'<?xml version="1.0" encoding="UTF-8"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/></Types>','_rels/.rels'=>'<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>','xl/workbook.xml'=>'<?xml version="1.0" encoding="UTF-8"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheets><sheet name="导入模板" sheetId="1" r:id="rId1"/></sheets></workbook>','xl/_rels/workbook.xml.rels'=>'<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/></Relationships>','xl/worksheets/sheet1.xml'=>'<?xml version="1.0" encoding="UTF-8"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData>'.implode('',$sheetRows).'</sheetData></worksheet>'];
    $zip=new ZipArchive();if($zip->open($path,ZipArchive::CREATE|ZipArchive::OVERWRITE)!==true)return false;foreach($files as$name=>$content)$zip->addFromString($name,$content);return$zip->close();
}
