<?php
namespace app\adminVue\controller;

use think\facade\Db;

/** Read-only desktop repair ledger. All writes stay in the existing mobile flow. */
class V2AfterSalesRepair extends V2Base
{
    private function number($key,$default,$max=9007199254740991)
    {
        $value=$this->request->get($key,$default);
        if ((!is_string($value)&&!is_int($value))||!preg_match('/^[1-9][0-9]{0,15}$/D',(string)$value)||(float)$value>$max) $this->fail('数字参数不正确');
        return (int)$value;
    }
    private function text($key,$max=100)
    {
        $value=$this->request->get($key,'');
        if (!is_string($value)||mb_strlen($value)>$max) $this->fail('查询参数不正确');
        return trim($value);
    }
    private function date($value,$time=false)
    {
        if (!is_string($value)) $this->fail('日期格式不正确');
        $format=$time?'Y-m-d H:i:s':'Y-m-d';
        $date=\DateTimeImmutable::createFromFormat('!'.$format,$value,new \DateTimeZone('Asia/Shanghai'));
        if (!$date||$date->format($format)!==$value||substr($value,0,10)<'2000-01-01'||substr($value,0,10)>'2099-12-31') $this->fail('日期格式不正确');
        return $date;
    }
    private function query($export=false)
    {
        $q=Db::name('after_sales_repair')->whereNull('deleted_at');
        $start=$this->request->get('startDate','');$end=$this->request->get('endDate','');
        if ($export&&($start===''||$end==='')) $this->fail('请选择导出日期区间');
        $first=$start!==''?$this->date($start):null;$last=$end!==''?$this->date($end):null;
        if ($first&&$last&&$first>$last) $this->fail('开始日期不能晚于结束日期');
        if ($first) $q->where('repair_at','>=',$first->format('Y-m-d H:i:s'));
        if ($last) $q->where('repair_at','<',$last->modify('+1 day')->format('Y-m-d H:i:s'));
        if (!$export) {
            $keyword=$this->text('keyword');$project=$this->text('project',50);$person=$this->text('personName');$area=$this->text('repairArea',30);
            if ($keyword!=='') $q->whereLike('record_no|trace_no|project|harness_name|problem_description','%'.addcslashes($keyword,'%_\\').'%');
            if ($project!=='') $q->where('project',$project);
            if ($area!=='') $q->where('repair_area',$area);
            if ($person!=='') {
                $ids=Db::name('admin_user')->whereLike('truename','%'.addcslashes($person,'%_\\').'%')->column('id');
                $q->whereIn('creator_id',$ids?:[0]);
            }
        }
        return $q;
    }
    private function fields()
    {
        return 'id,record_no,repair_at,trace_no,project,harness_name,problem_description,repair_method,repair_area,creator_id,remark,created_at,updated_at';
    }
    private function present($rows)
    {
        if (!$rows) return [];
        $ids=array_column($rows,'id');$names=Db::name('admin_user')->whereIn('id',array_unique(array_column($rows,'creator_id')))->column('truename','id');$assist=[];$images=[];
        foreach (Db::name('after_sales_repair_person')->alias('p')->leftJoin('admin_user a','a.id=p.admin_id')->whereIn('p.repair_id',$ids)->field('p.repair_id,p.admin_id,a.truename')->order('p.admin_id')->select() as $person) {
            $assist[$person['repair_id']][(int)$person['admin_id']]=$person['truename']?:'人员已变更';
        }
        foreach (Db::name('after_sales_repair_image')->whereIn('repair_id',$ids)->whereIn('image_type',[1,2])->field('id,repair_id,image_type')->order('id')->select() as $image) {
            $images[$image['repair_id']][(int)$image['image_type']][]=['id'=>(int)$image['id']];
        }
        $result=[];
        foreach ($rows as $row) {
            $people=$assist[$row['id']]??[];unset($people[(int)$row['creator_id']]);
            $result[]=['id'=>(int)$row['id'],'recordNo'=>$row['record_no'],'repairAt'=>substr($row['repair_at'],0,16),
                'traceNo'=>$row['trace_no'],'project'=>$row['project'],'harnessName'=>$row['harness_name'],'problemDescription'=>$row['problem_description'],
                'repairMethod'=>$row['repair_method'],'repairArea'=>$row['repair_area'],'remark'=>$row['remark'],
                'repairerName'=>$names[$row['creator_id']]??'人员已变更','assistantNames'=>implode('、',array_values($people)),
                'faultImages'=>$images[$row['id']][1]??[],'completedImages'=>$images[$row['id']][2]??[],
                'createdAt'=>$row['created_at'],'updatedAt'=>$row['updated_at']];
        }
        return $result;
    }
    public function index()
    {
        $page=$this->number('page',1,1000000);$limit=$this->number('limit',15,100);$q=$this->query();$total=(clone $q)->count();
        return json(['code'=>0,'msg'=>'','data'=>['list'=>$this->present($q->field($this->fields())->order('repair_at desc,id desc')->page($page,$limit)->select()->toArray()),'total'=>$total]]);
    }
    public function options()
    {
        $projects=Db::name('after_sales_repair')->whereNull('deleted_at')->distinct(true)->column('project');
        $areas=Db::name('after_sales_repair')->whereNull('deleted_at')->distinct(true)->column('repair_area');
        $clean=function($values){return array_values(array_unique(array_filter($values,function($v){return is_string($v)&&trim($v)!=='';})));};
        return json(['code'=>0,'msg'=>'','data'=>['projects'=>$clean(array_merge($this->app->config->get('daily_issue.projects',[]),$projects)),
            'areas'=>$clean(array_merge(['内饰区','底盘区','完成线/终线区','返修调试区','其他区域'],$areas)),
            'today'=>(new \DateTimeImmutable('now',new \DateTimeZone('Asia/Shanghai')))->format('Y-m-d')]]);
    }
    public function detail()
    {
        $row=Db::name('after_sales_repair')->where('id',$this->number('id',0))->whereNull('deleted_at')->field($this->fields())->find();
        if (!$row) $this->fail('维修记录不存在或已删除',404);
        return json(['code'=>0,'msg'=>'','data'=>$this->present([$row])[0]]);
    }
    public function export()
    {
        $q=$this->query(true);$upper=$this->request->get('upperId','');$upper=$upper===''?(int)(clone $q)->max('id'):$this->number('upperId',0);
        if (!$upper) return json(['code'=>0,'msg'=>'','data'=>['list'=>[],'total'=>0,'upperId'=>0,'nextCursor'=>null]]);
        $q->where('id','<=',$upper);$total=(clone $q)->count();$cursor=$this->text('cursor',50);
        if ($cursor!=='') {
            if (!preg_match('/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\|([1-9][0-9]{0,15})$/D',$cursor,$m)||(float)$m[2]>9007199254740991) $this->fail('导出游标不正确');
            $date=$this->date($m[1],true)->format('Y-m-d H:i:s');$id=(int)$m[2];
            $q->where(function($outer)use($date,$id){$outer->where('repair_at','<',$date)->whereOr(function($same)use($date,$id){$same->where('repair_at',$date)->where('id','<',$id);});});
        }
        $rows=$q->field($this->fields())->order('repair_at desc,id desc')->limit(201)->select()->toArray();$more=count($rows)>200;
        if ($more) array_pop($rows);$last=$rows?end($rows):null;
        return json(['code'=>0,'msg'=>'','data'=>['list'=>$this->present($rows),'total'=>$total,'upperId'=>$upper,'nextCursor'=>$more?$last['repair_at'].'|'.$last['id']:null]]);
    }
    public function exportImage()
    {
        $image=Db::name('after_sales_repair_image')->where('id',$this->number('imageId',0))->whereIn('image_type',[1,2])->field('repair_id,file_path')->find();
        $record=$image?Db::name('after_sales_repair')->where('id',$image['repair_id'])->whereNull('deleted_at')->value('id'):null;
        $path=str_replace('\\','/',(string)($image['file_path']??''));
        if (!$record||strpos($path,'/storage/')!==0||strpos($path,'..')!==false) $this->fail('图片不存在或维修记录已删除',404);
        $root=realpath($this->app->getRootPath().'public/storage/');$file=$root?realpath($root.'/'.substr($path,9)):false;
        if (!$file||strpos($file,$root.DIRECTORY_SEPARATOR)!==0||!is_file($file)) $this->fail('本地缺少该图片文件，请同步对应的 storage 图片目录',404);
        if (!is_readable($file)) $this->fail('图片文件无读取权限',403);
        if (filesize($file)>5*1024*1024) $this->fail('图片文件超过5MB，暂无法读取');
        $info=@getimagesize($file);
        if (!$info||!in_array($info['mime'],['image/jpeg','image/png','image/webp'],true)) $this->fail('图片格式不支持');
        $bytes=file_get_contents($file);if ($bytes===false) $this->fail('图片读取失败',503);
        return json(['code'=>0,'msg'=>'','data'=>['dataUrl'=>'data:'.$info['mime'].';base64,'.base64_encode($bytes)]]);
    }
}
