<?php
namespace app\mobile\controller;
use think\facade\Db;
use think\facade\Log;
use app\mobile\service\RadioAccess;
use app\mobile\service\WechatTemplateService;

class OmsRadio extends OmsBase
{
    protected function initialize() {
        parent::initialize();
        // 新点歌表支持祝福中的表情；只调整本请求的默认连接会话，不改全站配置。
        Db::execute('SET NAMES utf8mb4');
    }
    protected function now() { return time(); }
    private function result($data=null) { return json(['code'=>0,'message'=>'成功','data'=>$data]); }
    private function dateToday() { return substr(WechatTemplateService::time($this->now()),0,10); }
    private function number($value,$max=2147483647) {
        if ((!is_string($value)&&!is_int($value)) || !preg_match('/^[1-9][0-9]{0,9}$/D',(string)$value) || (float)$value>$max) $this->fail('数字参数不正确');
        return (int)$value;
    }
    private function date($value,$future=false) {
        if (!is_string($value) || !preg_match('/^20[0-9]{2}-[0-9]{2}-[0-9]{2}$/D',$value)) $this->fail('请选择有效日期');
        $date=\DateTimeImmutable::createFromFormat('!Y-m-d',$value,new \DateTimeZone('Asia/Shanghai'));
        if (!$date || $date->format('Y-m-d')!==$value || ($future && $value<$this->dateToday())) $this->fail('播放日期须为今天或未来日期');
        return $value;
    }
    private function text($key,$max,$required=true) {
        $value=$this->request->post($key,'');
        if (!is_string($value) || mb_strlen(trim($value))>$max || preg_match('/[\x00-\x08\x0B\x0C\x0E-\x1F]/u',$value)) $this->fail('填写内容格式或长度不正确');
        $value=trim($value); if ($required && $value==='') $this->fail('请填写完整'); return $value;
    }
    private function requireOperator($account,$lock=false) { if (!RadioAccess::operator($account,$lock)) $this->fail('没有播音室操作权限，请联系管理员授权',403); }
    private function present($row,$account,$operator) {
        $own=(int)$row['account_id']===(int)$account['id'];$pending=(int)$row['status']===1;
        return ['id'=>(int)$row['id'],'song'=>$row['song'],'singer'=>$row['singer'],'target'=>$row['target'],'blessing'=>$row['blessing'],
            'applicantName'=>$row['employee_name'],'employeeNo'=>$row['employee_no'],'date'=>$row['play_date'],'shift'=>(int)$row['shift'],'slot'=>(int)$row['slot'],
            'status'=>(int)$row['status'],'statusName'=>[1=>'待播放',2=>'已播放',3=>'已取消'][(int)$row['status']],
            'cancelReason'=>$row['cancel_reason'],'handlerName'=>$row['handler_name'],'createdAt'=>WechatTemplateService::time($row['created_at']),
            'playedAt'=>$row['played_at']?WechatTemplateService::time($row['played_at']):'',
            'notificationStatus'=>(int)$row['notification_status'],'canWithdraw'=>$own&&$pending,'canManage'=>$operator&&$pending];
    }
    public function options() {
        return $this->guarded(function () { $this->requireMethod('GET');$a=$this->current();return $this->result(['canManage'=>RadioAccess::operator($a),'today'=>$this->dateToday()]); });
    }
    public function records() {
        return $this->guarded(function () {
            $this->requireMethod('GET');$a=$this->current();$scope=$this->request->get('scope','mine');
            if (!in_array($scope,['mine','station'],true)) $this->fail('查看类型不正确');
            $operator=false;$query=Db::name('radio_request');
            if ($scope==='station') {
                $operator=RadioAccess::operator($a);
                $date=$this->request->get('date','');if($date!=='')$query->where('play_date',$this->date($date));
                foreach(['shift','slot'] as $field){$value=$this->request->get($field,'');if($value!=='')$query->where($field,$this->number($value,2));}
            } else $query->where('account_id',$a['id']);
            $status=$this->request->get('status','');if($status!=='')$query->where('status',$this->number($status,3));
            $keyword=$this->request->get('keyword','');if(!is_string($keyword)||mb_strlen($keyword)>50)$this->fail('搜索内容最多50字');
            if(trim($keyword)!=='')$query->whereLike('song|target|employee_name','%'.addcslashes(trim($keyword),'%_\\').'%');
            $page=$this->number($this->request->get('page',1),100000);$total=(clone $query)->count();
            $rows=$query->order($scope==='station'?'id asc':'id desc')->page($page,15)->select()->toArray();
            return $this->result(['items'=>array_map(function($r)use($a,$operator){return $this->present($r,$a,$operator);},$rows),'total'=>$total,'page'=>$page]);
        });
    }
    public function detail() {
        return $this->guarded(function () {
            $this->requireMethod('GET');$a=$this->current();$id=$this->number($this->request->get('id'));$row=Db::name('radio_request')->find($id);
            if(!$row)$this->fail('点歌申请不存在',404);$operator=RadioAccess::operator($a);
            return $this->result($this->present($row,$a,$operator));
        });
    }
    public function create() {
        return $this->guarded(function () {
            $this->requireMethod('POST');$a=$this->current();$person=RadioAccess::person($a);if(!$person)$this->fail('账号已失效',403);
            $key=$this->text('requestKey',64);if(!preg_match('/^[a-zA-Z0-9_-]{16,64}$/D',$key))$this->fail('提交标识无效，请重新打开页面');
            $form=['song'=>$this->text('song',100),'singer'=>$this->text('singer',100,false),'target'=>$this->text('target',100),'blessing'=>$this->text('blessing',500),
                'play_date'=>$this->date($this->request->post('date')),'shift'=>$this->number($this->request->post('shift'),2),'slot'=>$this->number($this->request->post('slot'),2)];
            $hash=hash('sha256',json_encode($form,JSON_UNESCAPED_UNICODE));
            $existing=Db::name('radio_request')->where(['account_id'=>$a['id'],'request_key'=>$key])->find();
            if(!$existing) {
                $this->date($form['play_date'],true);
                try {
                    $id=Db::name('radio_request')->insertGetId($form+['account_id'=>$a['id'],'employee_no'=>$a['username'],'employee_name'=>$person['name'],'created_at'=>$this->now(),'updated_at'=>$this->now(),'request_key'=>$key,'payload_hash'=>$hash]);
                    return $this->result(['id'=>(int)$id,'created'=>true]);
                } catch (\Throwable $error) {
                    $existing=Db::name('radio_request')->where(['account_id'=>$a['id'],'request_key'=>$key])->find();if(!$existing)throw $error;
                }
            }
            if(!hash_equals($existing['payload_hash'],$hash))$this->fail('提交标识已用于其他内容，请重新提交',409);
            return $this->result(['id'=>(int)$existing['id'],'created'=>false]);
        });
    }
    protected function notifyPlayed($row) {
        $service=$this->templateService();
        $slotLabel=($row['shift']==1?['上午休息时段','下午休息时段']:['上半夜休息时段','下半夜休息时段'])[(int)$row['slot']-1];
        $ok=$service->send('feedback_result',$service->employees([$row['employee_no']]),[
            'type'=>'点歌已播放','content'=>$row['song'].' · '.$row['target'],'owner'=>$row['handler_name'],
            'reply'=>$row['play_date'].' '.$slotLabel,'time'=>WechatTemplateService::time($row['played_at'])
        ],'pages/radio/detail?id='.$row['id']);
        return [$ok,$ok?'':$service->lastFailure()];
    }
    private function change($action) {
        return $this->guarded(function ()use($action) {
            $this->requireMethod('POST');$a=$this->current();$id=$this->number($this->request->post('id'));
            $reason=$action==='cancel'?$this->text('reason',255):'';
            Db::startTrans();
            try {
                if($action!=='withdraw')$this->requireOperator($a,true);
                $row=Db::name('radio_request')->lock(true)->find($id);if(!$row)$this->fail('点歌申请不存在',404);
                if($action==='withdraw'&&(int)$row['account_id']!==(int)$a['id'])$this->fail('只能撤回本人的点歌申请',403);
                if((int)$row['status']!==1)$this->fail('申请已处理，请刷新列表',409);
                $person=RadioAccess::person($a);if(!$person)$this->fail('账号已失效',403);
                $changes=['status'=>$action==='played'?2:3,'cancel_reason'=>$action==='withdraw'?'申请人撤回':$reason,'handler_id'=>$a['id'],'handler_name'=>$person['name'],'updated_at'=>$this->now()];
                if($action==='played')$changes+=['played_at'=>$this->now(),'notification_status'=>1];
                $changed=Db::name('radio_request')->where(['id'=>$id,'status'=>1])->update($changes);if(!$changed)$this->fail('申请已处理，请刷新',409);
                Db::commit();$row=array_merge($row,$changes);
            } catch (\Throwable $error) { Db::rollback();throw $error; }
            $notice=null;
            if($action==='played') {
                try { list($notice,$error)=$this->notifyPlayed($row); }
                catch(\Throwable $failure) { $notice=false;$error='模板通知发送异常，请查看服务端日志';Log::warning('radio template failed: request='.$id.', type='.get_class($failure)); }
                Db::name('radio_request')->where(['id'=>$id,'notification_status'=>1])->update(['notification_status'=>$notice?2:3,'notification_error'=>mb_substr((string)$error,0,500)]);
            }
            return $this->result(['notificationAccepted'=>$notice]);
        });
    }
    public function played() { return $this->change('played'); }
    public function cancel() { return $this->change('cancel'); }
    public function withdraw() { return $this->change('withdraw'); }
}
