<?php
namespace app\adminVue\controller;

use think\facade\Db;

/** Desktop read-only Daily Issue ledger; mobile remains the writer. */
class V2DailyIssue extends V2Base
{
    private function number($key,$default,$max=2147483647)
    {
        $v=$this->request->get($key,$default);
        if ((!is_string($v)&&!is_int($v))||!preg_match('/^[1-9][0-9]{0,9}$/D',(string)$v)||(float)$v>$max) $this->fail('数字参数不正确');
        return (int)$v;
    }
    private function text($key,$max=100)
    {
        $v=$this->request->get($key,'');
        if (!is_string($v)||mb_strlen($v)>$max) $this->fail('查询参数不正确');
        return trim($v);
    }
    private function date($value)
    {
        if (!is_string($value)) $this->fail('日期格式不正确');
        $date=\DateTimeImmutable::createFromFormat('!Y-m-d',$value,new \DateTimeZone('Asia/Shanghai'));
        if (!$date||$date->format('Y-m-d')!==$value||$value<'2000-01-01'||$value>'2099-12-31') $this->fail('日期格式不正确');
        return $date->getTimestamp();
    }
    private function query($export=false)
    {
        $q=Db::name('quality_wir_list')->whereIn('status',[1,2])->where('wirDate','>',0);
        $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!==null&&$last!==null&&$first>$last) $this->fail('开始日期不能晚于结束日期');
        if ($first!==null) $q->where('wirDate','>=',$first);
        if ($last!==null) $q->where('wirDate','<',$last+86400);
        if (!$export) {
            $keyword=$this->text('keyword');$project=$this->text('project',50);$person=$this->text('personName');$status=$this->request->get('status','');
            if ($keyword!=='') $q->whereLike('project|dpn|station|desc','%'.addcslashes($keyword,'%_\\').'%');
            if ($project!=='') $q->where('project',$project);
            if ($person!=='') {
                $ids=Db::name('admin_user')->whereLike('truename','%'.addcslashes($person,'%_\\').'%')->column('id');
                $q->whereIn('owner',$ids?:[0]);
            }
            if ($status!=='') {
                if ((!is_int($status)&&!is_string($status))||!in_array((string)$status,['1','2'],true)) $this->fail('状态不正确');
                $q->where('status',(int)$status);
            }
        }
        return $q;
    }
    private function fields()
    {
        return 'id,wirDate,project,dpn,issueDate,station,desc,repair,checkQty,allNgQty,reason,back,ngQty,remark,duty,status,owner,update,updated_at,published_at,publisher_id';
    }
    private function formatted($value,$format='Y-m-d H:i')
    {
        return (int)$value>0?(new \DateTimeImmutable('@'.(int)$value))->setTimezone(new \DateTimeZone('Asia/Shanghai'))->format($format):'';
    }
    private function present($rows)
    {
        if (!$rows) return [];
        $ids=array_unique(array_merge(array_column($rows,'owner'),array_column($rows,'publisher_id')));
        $names=Db::name('admin_user')->whereIn('id',$ids)->column('truename','id');$images=[];
        foreach (Db::name('img_list')->where(['mid'=>55,'status'=>1])->whereIn('mark',array_column($rows,'id'))->field('id,mark')->order('id')->select() as $image) {
            $images[$image['mark']][]=['id'=>(int)$image['id']];
        }
        $result=[];
        foreach ($rows as $row) {
            $item=['id'=>(int)$row['id'],'wirDate'=>$this->formatted($row['wirDate'],'Y-m-d'),'issueDate'=>$this->formatted($row['issueDate'],'Y-m-d'),
                'ownerName'=>$names[$row['owner']]??'人员已变更','dutyName'=>[1=>'TBD',2=>'WIR',3=>'Daily Issue'][(int)$row['duty']]??'',
                'backName'=>[1=>'是',2=>'否'][(int)$row['back']]??'','status'=>(int)$row['status'],'statusName'=>(int)$row['status']===2?'已发布':'待发布',
                'createdAt'=>$this->formatted($row['update']),'updatedAt'=>$this->formatted($row['updated_at']),
                'publishedAt'=>$this->formatted($row['published_at']),'publisherName'=>$names[$row['publisher_id']]??'','images'=>$images[$row['id']]??[]];
            foreach (['project','dpn','station','desc','repair','checkQty','allNgQty','reason','ngQty','remark'] as $field) $item[$field]=(string)$row[$field];
            $result[]=$item;
        }
        return $result;
    }
    public function index()
    {
        $page=$this->number('page',1,1000000);$limit=$this->number('limit',15,100);$q=$this->query();
        $total=(clone $q)->count();$rows=$q->field($this->fields())->order('wirDate desc,id desc')->page($page,$limit)->select()->toArray();
        return json(['code'=>0,'msg'=>'','data'=>['list'=>$this->present($rows),'total'=>$total]]);
    }
    public function options()
    {
        $configured=$this->app->config->get('daily_issue.projects',[]);
        $actual=Db::name('quality_wir_list')->whereIn('status',[1,2])->where('wirDate','>',0)->distinct(true)->column('project');
        $projects=array_values(array_unique(array_filter(array_merge($configured,$actual),function($v){return is_string($v)&&trim($v)!=='';})));
        return json(['code'=>0,'msg'=>'','data'=>['projects'=>$projects,'today'=>(new \DateTimeImmutable('now',new \DateTimeZone('Asia/Shanghai')))->format('Y-m-d')]]);
    }
    public function detail()
    {
        $id=$this->number('id',0);$row=Db::name('quality_wir_list')->where('id',$id)->whereIn('status',[1,2])->where('wirDate','>',0)->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',30);
        if ($cursor!=='') {
            if (!preg_match('/^([1-9][0-9]{0,9}):([1-9][0-9]{0,9})$/D',$cursor,$m)||(float)$m[2]>2147483647||(float)$m[1]>4102444799) $this->fail('导出游标不正确');
            $date=(int)$m[1];$id=(int)$m[2];
            $q->where(function($outer)use($date,$id){$outer->where('wirDate','<',$date)->whereOr(function($same)use($date,$id){$same->where('wirDate',$date)->where('id','<',$id);});});
        }
        // Bounded reads with a date/ID cursor avoid loading the whole ledger into PHP memory.
        $rows=$q->field($this->fields())->order('wirDate 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['wirDate'].':'.$last['id']:null]]);
    }
    protected function imageRoot() { return $this->app->getRootPath().'public/storage/'; }
    public function exportImage()
    {
        $id=$this->number('imageId',0);$image=Db::name('img_list')->where(['id'=>$id,'mid'=>55,'status'=>1])->field('mark,img')->find();
        $record=$image?Db::name('quality_wir_list')->where('id',$image['mark'])->whereIn('status',[1,2])->where('wirDate','>',0)->value('id'):null;
        $path=str_replace('\\','/',(string)($image['img']??''));
        if (!$record||strpos($path,'/storage/')!==0||strpos($path,'..')!==false) $this->fail('图片不存在或记录已作废',404);
        $root=realpath($this->imageRoot());$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)]]);
    }
}
