<?php
namespace app\mobile\controller;

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

class OmsLeaveApply extends OmsBase
{
    public static function memberFor($account)
    {
        if ((int)($account['user_id'] ?? 0) <= 0) return null;
        return Db::name('member_list')->where(['id'=>$account['user_id'],'eid'=>$account['username'],'status'=>1])->find();
    }
    private function member($account)
    {
        $member = self::memberFor($account);
        if (!$member) $this->fail('仅关联在职员工的本人可申请离职',403);
        return $member;
    }
    private function result($data) { return json(['code'=>0,'message'=>'成功','data'=>$data]); }
    private function id($value)
    {
        if (!is_scalar($value) || !preg_match('/^[1-9][0-9]{0,9}$/',(string)$value) || (float)$value > 2147483647) $this->fail('请选择有效选项');
        return (int)$value;
    }
    protected function now() { return time(); }
    private function dates($member)
    {
        $zone = new \DateTimeZone('Asia/Shanghai');
        $today = (new \DateTimeImmutable('@'.$this->now()))->setTimezone($zone)->setTime(0,0);
        $hire = (new \DateTimeImmutable('@'.(int)$member['hiredate']))->setTimezone($zone)->setTime(0,0);
        if ((int)$member['hiredate'] <= 0 || $hire > $today) $this->fail('入职日期异常，请联系HR核对',409);
        $trial = $today->modify('+3 days');
        $days = (int)$hire->diff($trial)->format('%a') >= 30 ? 15 : 3;
        $expected = $today->modify('+'.$days.' days');
        return ['hireDate'=>$hire->format('Y-m-d'),'expectedLeaveDate'=>$expected->format('Y-m-d'),'timestamp'=>$expected->getTimestamp(),'noticeDays'=>$days];
    }
    private function pending($member)
    {
        $rows = Db::name('member_perleave')->where(['mid'=>$member['id'],'status'=>1])->order('id desc')->limit(2)->select()->toArray();
        if (count($rows) > 1) $this->fail('存在多条预离职申请，请联系HR核对',409);
        return $rows[0] ?? null;
    }
    private function present($row)
    {
        $type = Db::name('member_base')->find($row['type']);
        return ['id'=>(int)$row['id'],'team'=>Db::name('team_list')->where('id',$row['tid'])->value('team') ?: '班组信息缺失',
            'leaderName'=>Db::name('admin_user')->where('id',$row['aid'])->value('truename') ?: '班长信息缺失',
            'typeName'=>$type ? trim($type['title'].' - '.$type['content']) : '类型信息缺失',
            'reason'=>(string)$row['reason'],'expectedLeaveDate'=>empty($row['perleave_date']) ? '' : date('Y-m-d',$row['perleave_date'])];
    }
    public function options()
    {
        return $this->guarded(function () {
            $this->requireMethod('GET'); $member = $this->member($this->current()); $pending = $this->pending($member);
            $teams = Db::name('team_list')->where('status',1)->field('id,team,project,aid')->order('project,team,id')->select()->toArray();
            $projects = Db::name('team_base')->where('mid',1)->column('title','id');
            foreach ($teams as &$team) { $team['id']=(int)$team['id']; $team['project']=(int)$team['project']; $team['aid']=(int)$team['aid']; $team['projectName']=$projects[$team['project']] ?? '其他班组'; } unset($team);
            $leaders = Db::name('admin_user')->where(['status'=>1,'job'=>9])->field('id,truename as name')->order('truename,id')->select()->toArray();
            foreach ($leaders as &$leader) $leader['id']=(int)$leader['id']; unset($leader);
            $types = Db::name('member_base')->where(['mid'=>1,'mark'=>1])->where('id','>',100)->where('id','<',300)->field('id,title,content')->order('title,id')->select()->toArray();
            $types = array_map(function ($type) { return ['id'=>(int)$type['id'],'name'=>trim($type['title'].' - '.$type['content'])]; },$types);
            $dates = null; $block = '';
            try { $dates = $this->dates($member); } catch (\think\exception\HttpResponseException $error) { $block = '入职日期异常，请联系HR核对'; }
            $defaultTeam = null;
            foreach ($teams as $team) if ($team['id'] === (int)$member['tid']) $defaultTeam=$team;
            $defaultLeader = $defaultTeam && in_array($defaultTeam['aid'],array_column($leaders,'id'),true) ? $defaultTeam['aid'] : 0;
            return $this->result(['employee'=>['name'=>$member['ename'],'employeeNo'=>$member['eid']],
                'teams'=>$teams,'leaders'=>$leaders,'types'=>$types,'defaultTeamId'=>$defaultTeam ? $defaultTeam['id'] : 0,'defaultLeaderId'=>$defaultLeader,
                'hireDate'=>$dates['hireDate'] ?? '', 'expectedLeaveDate'=>$dates['expectedLeaveDate'] ?? '', 'noticeDays'=>$dates['noticeDays'] ?? 0,
                'blockReason'=>$block,'current'=>$pending ? $this->present($pending) : null]);
        });
    }
    private function writeLock($action)
    {
        $prefix=$this->app->config->get('database.connections.'.$this->app->config->get('database.default').'.prefix');
        if (!preg_match('/^[a-zA-Z0-9_]+$/',$prefix)) throw new \RuntimeException('Invalid prefix');
        Db::query('SELECT 1'); $connection=Db::connect()->getConnection(); $pdo=$connection->getPdo();
        $pdo->exec("LOCK TABLES `{$prefix}member_perleave` WRITE, `{$prefix}member_list` READ, `{$prefix}team_list` READ, `{$prefix}admin_user` READ, `{$prefix}member_base` READ");
        try { return $action(); } finally { $connection->free(); $pdo->exec('UNLOCK TABLES'); }
    }
    public function apply()
    {
        return $this->guarded(function () {
            $this->requireMethod('POST'); $account=$this->current(); $this->member($account);
            $saved=$this->writeLock(function () use ($account) {
                $member=$this->member($account); $pending=$this->pending($member);
                if ($pending) return ['row'=>$pending,'member'=>$member,'created'=>false];
                $tid=$this->id($this->request->post('teamId')); $aid=$this->id($this->request->post('leaderId')); $typeId=$this->id($this->request->post('typeId'));
                $team=Db::name('team_list')->where(['id'=>$tid,'status'=>1])->find();
                $leader=Db::name('admin_user')->where(['id'=>$aid,'status'=>1,'job'=>9])->find();
                $type=Db::name('member_base')->where(['id'=>$typeId,'mid'=>1,'mark'=>1])->where('id','>',100)->where('id','<',300)->find();
                if (!$team || !$leader || !$type) $this->fail('班组、班长或离职类型已失效，请刷新重新选择',409);
                $reason=$this->request->post('reason');
                if (!is_string($reason) || trim($reason)==='' || mb_strlen(trim($reason))>255) $this->fail('请填写离职原因，最多255字');
                $dates=$this->dates($member);
                if ($this->request->post('teamName')!==$team['team'] || $this->request->post('leaderName')!==$leader['truename'] || $this->request->post('typeName')!==trim($type['title'].' - '.$type['content']) || $this->request->post('expectedLeaveDate')!==$dates['expectedLeaveDate']) $this->fail('申请信息已变化，请刷新后重新核对班组、班长及预计日期',409);
                // 保存员工确认的选择，不覆盖为同步资料中的tid/aid，也不回写基础资料。
                $row=['mid'=>(int)$member['id'],'tid'=>$tid,'aid'=>$aid,'type'=>$typeId,'reason'=>trim($reason),'status'=>1,'perleave_date'=>$dates['timestamp'],'update'=>$this->now()];
                $row['id']=(int)Db::name('member_perleave')->insertGetId($row);
                return ['row'=>$row,'member'=>$member,'created'=>true];
            });
            if ($saved['created']) $this->notifyApplication($saved);
            return $this->result(['created'=>$saved['created'],'current'=>$this->present($saved['row'])]);
        });
    }
    protected function notifyApplication($saved)
    {
        try {
            $service=$this->templateService();$row=$saved['row'];
            return $service->send('workflow_pending',$service->admins([$row['aid']]),[
                'name'=>'员工离职申请','initiator'=>$saved['member']['ename'],'time'=>$service::time($row['update']),
                'reason'=>$row['reason'],'step'=>'班长处理',
            ],'pages/leave-cancel/detail?id='.$row['id']);
        } catch (\Throwable $error) { Log::warning('oms leave application notification unavailable: '.$error->getMessage()); return false; }
    }
}
