<?php
namespace app\mobile\controller;

use think\facade\Db;
use think\facade\Log;

/** 领餐登记与制码；扫码核销仍由原食堂 APP 处理。 */
class OmsMeal extends OmsBase
{
    private const MEALS = [1=>'白班午餐', 2=>'白班晚餐', 3=>'夜班夜宵', 4=>'夜班早餐', 5=>'其他', 6=>'白班晚餐简餐', 7=>'客户餐'];
    protected function now() { return time(); }
    private function optionalAccount() {
        $header = $this->request->header('authorization', '') ?: $this->request->server('HTTP_AUTHORIZATION', '') ?: $this->request->server('REDIRECT_HTTP_AUTHORIZATION', '');
        return $header === '' ? null : $this->current();
    }
    private function dateValue($text) {
        if (!is_string($text)) $this->fail('请选择有效的用餐日期');
        $date = \DateTimeImmutable::createFromFormat('!Y-m-d', $text, new \DateTimeZone('Asia/Shanghai'));
        if (!$date || $date->format('Y-m-d') !== $text || $date->getTimestamp() < 0 || $date->getTimestamp() > 2147483647) $this->fail('请选择有效的用餐日期');
        return $date->getTimestamp();
    }
    private function integer($value, $label) {
        if (!is_scalar($value) || !preg_match('/^[1-9][0-9]{0,9}$/', (string)$value) || (float)$value > 2147483647) $this->fail($label . '不正确');
        return (int)$value;
    }
    private function today() { return strtotime(date('Y-m-d', $this->now())); }
    public function options() {
        return $this->guarded(function () {
            $this->requireMethod('GET'); $account = $this->optionalAccount();
            $meals = [];
            foreach (self::MEALS as $id=>$label) if ($id !== 7 || ($account && (int)$account['user_type'] > 1)) $meals[] = ['id'=>$id, 'label'=>$label];
            $date = date('Y-m-d', $this->now() - 8 * 3600);
            return json(['code'=>0, 'message'=>'成功', 'data'=>['meals'=>$meals, 'defaultDate'=>$date, 'trainingAllowed'=>!$account]]);
        });
    }
    public function visitors() {
        return $this->guarded(function () {
            $this->requireMethod('GET'); $account = $this->current();
            if (!OmsVisitor::adminFor($account)) $this->fail('当前账号没有访客领餐登记', 403);
            $date = $this->dateValue($this->request->get('date'));
            $rows = Db::name('common_visitor_list')->where('owner', $account['admin_id'])->where('status', 2)->where('start', '<=', $date)->where('end', '>=', $date)
                ->field('id,reason,num,start,end')->order('id desc')->select()->toArray();
            foreach ($rows as &$row) { $row['id'] = (int)$row['id']; $row['num'] = (int)$row['num']; $row['start'] = date('Y-m-d', $row['start']); $row['end'] = date('Y-m-d', $row['end']); }
            unset($row);
            return json(['code'=>0, 'message'=>'成功', 'data'=>['items'=>$rows]]);
        });
    }
    private function locked($identity, $action) {
        $database = $this->app->config->get('database.connections.' . $this->app->config->get('database.default') . '.database');
        $key = 'oms-meal:' . sha1($database . ':' . $identity);
        $result = Db::query('SELECT GET_LOCK(?, 5) AS acquired', [$key]);
        if ((int)$result[0]['acquired'] !== 1) $this->fail('正在生成领餐码，请稍后重试', 503);
        try { return $action(); } finally { Db::query('SELECT RELEASE_LOCK(?)', [$key]); }
    }
    private function ticket($row, $note = '') {
        return ['ticket'=>'ticket.' . $row['type'] . '.' . $row['item'] . '.' . $row['id'] . '.' . $row['create_time'], 'id'=>(int)$row['id'], 'num'=>(int)$row['num'], 'date'=>date('Y-m-d', $row['meal_date']), 'item'=>(int)$row['item'], 'type'=>(int)$row['type'], 'note'=>$note];
    }
    protected function notifyMeal($row) {
        if (!in_array((int)$row['type'], [4,5], true)) return;
        $customer = (int)$row['type'] === 5;
        $recipients = $customer ? [315,2,657] : [436,2,315];
        $template = ['type'=>2, 'template_id'=>'lRduti-4_32yG9ZDuLApgFufCBZWgd404SrNdOWRhgw', 'data'=>[
            'thing4'=>['value'=>($customer ? '' : self::MEALS[$row['item']] . ',') . '原因：' . $row['mark'], 'color'=>'#FF0000'],
            'character_string8'=>['value'=>date('Y-m-d', $row['meal_date']) . ($customer ? '' : ' , ' . $row['num'] . 'set'), 'color'=>'#FF0000'],
            'thing3'=>['value'=>$row['ename'] . ($customer ? ' 领客户餐' . $row['num'] . '份！' : ' 批量领餐'), 'color'=>'#FF0000'],
        ]];
        foreach ($recipients as $recipient) {
            try { $template['touser'] = $recipient; $result = (new \wx\wxMsg())->send_msg(json_encode($template)); if ((string)$result !== '0') Log::warning('oms meal notification failed'); }
            catch (\Throwable $exception) { Log::warning('oms meal notification unavailable'); }
        }
    }
    public function generate() {
        return $this->guarded(function () {
            $this->requireMethod('POST');
            $date = $this->dateValue($this->request->post('date'));
            $item = $this->integer($this->request->post('item'), '餐别'); $type = $this->integer($this->request->post('type'), '领餐原因');
            if (!isset(self::MEALS[$item]) || $type > 5 || (($item === 7) !== ($type === 5))) $this->fail('请选择正确的餐别和领餐原因');
            $account = $type === 1 ? $this->optionalAccount() : $this->current();
            if ($type === 1 && $account) $this->fail('非培训期员工，请选择其他领餐原因');
            if ($item === 7 && (int)$account['user_type'] <= 1) $this->fail('当前账号不能领取客户餐', 403);
            $data = ['meal_date'=>$date, 'item'=>$item, 'type'=>$type, 'eid'=>$account ? (string)$account['username'] : '', 'ename'=>'', 'num'=>1,
                'itemMark'=>$item === 5 ? $this->requiredText('itemMark', 300) : '', 'mark'=>'', 'mark_type'=>null, 'phone'=>'', 'visitor_id'=>null];
            if ($item === 5 && mb_strlen($data['itemMark'], 'UTF-8') > 100) $this->fail('其他餐名不能超过100字');
            $key = ['meal_date'=>$date, 'item'=>$item, 'type'=>$type];
            if ($type === 1) {
                $phone = $this->requiredText('phone', 11);
                if (!preg_match('/^[0-9]{11}$/', $phone)) $this->fail('请输入11位手机号');
                $newcomer = Db::name('member_newcomer')->where('phone', $phone)->where('create_time', '>', $this->today() - 86400)->order('id desc')->find();
                if (!$newcomer) $this->fail('未查询到该手机号的有效培训记录');
                $data['phone'] = $phone; $data['ename'] = $newcomer['name']; $key['phone'] = $phone;
            } else {
                $source = (int)$account['user_type'] > 1 ? 'admin_user' : 'member_list';
                $person = Db::name($source)->find((int)$account['user_type'] > 1 ? $account['admin_id'] : $account['user_id']);
                $data['ename'] = $person[(int)$account['user_type'] > 1 ? 'truename' : 'ename'];
                if ($type === 3) {
                    if (!OmsVisitor::adminFor($account)) $this->fail('当前账号没有访客领餐登记', 403);
                    $visitorId = $this->integer($this->request->post('visitor_id'), '访客登记');
                    $visitor = Db::name('common_visitor_list')->where('id', $visitorId)->where('owner', $account['admin_id'])->where('status', 2)->where('start', '<=', $date)->where('end', '>=', $date)->find();
                    if (!$visitor) $this->fail('访客登记不存在、已失效或不属于当前账号');
                    $data['num'] = $this->integer($this->request->post('num'), '领餐数量');
                    if ($data['num'] > (int)$visitor['num']) $this->fail('领餐数量不能超过访客人数');
                    $data['visitor_id'] = $visitorId; $key['visitor_id'] = $visitorId;
                } else {
                    $key['eid'] = $data['eid'];
                    if ($type === 4 || $type === 5) {
                        $data['mark'] = $this->requiredText('mark', 765);
                        if (mb_strlen($data['mark'], 'UTF-8') > 255) $this->fail('原因说明不能超过255字');
                        if ($type === 4) {
                            $data['mark_type'] = $this->integer($this->request->post('mark_type'), '领餐方式');
                            if (!in_array($data['mark_type'], [1,2], true)) $this->fail('请选择个人或批量领餐');
                        }
                        if ($type === 5 || $data['mark_type'] === 2) $data['num'] = $this->integer($this->request->post('num'), '领餐数量');
                    }
                }
            }
            $created = null;
            $result = $this->locked(json_encode($key), function () use ($key, $data, $account, &$created) {
                $row = Db::name('common_meal_sign')->where($key)->find();
                if ($row && (int)$row['status'] !== 1) $this->fail('已验餐，不能再次生成领餐码');
                if ($data['type'] === 4 && (int)$account['user_type'] > 1) {
                    $admin = Db::name('admin_user')->find($account['admin_id']);
                    if ((int)$admin['job'] === 73) {
                        if ($data['meal_date'] !== $this->today()) $this->fail('劳务公司领餐仅限当天');
                        $total = Db::name('member_newcomer')->where('creator', $account['admin_id'])->where('create_time', '>', $this->today())->count();
                        if ($data['num'] > $total) $this->fail('领餐人数不能超过今天录入的新员工人数');
                    }
                }
                if ($row) {
                    if (in_array($data['type'], [3,4,5], true) && (int)$row['num'] !== $data['num']) {
                        // 保留创建时间，使已有二维码与核销 APP 保持兼容。
                        $note = '数量由 ' . $row['num'] . ' 修改为 ' . $data['num'];
                        $updated = Db::name('common_meal_sign')->where('id', $row['id'])->where('status', 1)->update($data);
                        if (!$updated) $this->fail('已验餐，不能修改领餐数量');
                        $row = array_merge($row, $data);
                        return $this->ticket($row, $note);
                    }
                    return $this->ticket($row);
                }
                $data['status'] = 1; $data['create_time'] = $this->now();
                $data['id'] = Db::name('common_meal_sign')->insertGetId($data);
                $created = $data;
                return $this->ticket($data);
            });
            if ($created) $this->notifyMeal($created);
            return json(['code'=>0, 'message'=>'领餐码已生成', 'data'=>$result]);
        });
    }
}
