<?php

namespace app\controller\api\v1;

use app\controller\api\Base;
use app\exception\RepositoryException;
use app\model\Account;
use app\model\AccountRecord;
use app\repository\AccountRepository;
use app\service\File;
use app\service\Jwt;
use app\service\wx\WechatApplets;
use app\validate\User as UserValidate;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use Exception;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Log;
use think\response\Json;

class User extends Base
{
    protected $noNeedLogin = [
        'login',
        'tempLogin',
        'signInfo',
        'signToday',
        'checkActive'
    ];

    /**
     * 登录  成功返回token及用户信息
     *
     * @return Json
     * @throws InvalidConfigException
     */
    public function login(): Json
    {
        $params = input();

        Log::error('进入参数');
        Log::error($params);
        Log::error('参数结束');
        $validate = new UserValidate();
        if (!$validate->scene('wx_applets')->check($params)) {
            return $this->json(4000, $validate->getError());
        }
        $minApp = WechatApplets::getInstance();
        $jsCode = $params['code'];
        $wxUser = $minApp->auth->session($jsCode);

        if (isset($wxUser['errcode']) && $wxUser['errcode'] != 0) {
            return $this->json(4001, $wxUser['errcode'].';'.$wxUser['errmsg'] ?? '登录失败');
        }
        // $wxUser success has [session_key, openid, unionid]
        // 有效期2小时
        $wxUser['expire_time'] = time() + 7200;
        $wxUser['session_key'] = $wxUser['session_key'] ?? '';
        $openID                = $wxUser['openid'];
        $unionid               = $wxUser['unionid'] ?? '';

        if (empty($openID) && empty($unionid)) {
            return $this->json(4002, '登录失败');
        }
        $isActive    = $params['is_active'] ?? 0;
        $isActive    = (is_numeric($isActive) && $isActive > 0) ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
        $phoneActive = $params['phone_active'] ?? 0;
        $phoneActive = (is_numeric($phoneActive) && $phoneActive > 0) ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;

        try {
            $repo    = AccountRepository::getInstance();
            $account = $repo->findByOpenID($openID);
            if (!$account && !empty($unionid)) {
                $account = $repo->findByUnionId($unionid);
            }

            $now = date('Y-m-d H:i:s');
            if (!$account) {
                // 自动注册
                $account = $repo->create([
                    'unionid'      => $unionid ?? '',
                    'openid'       => $openID,
                    'last_login'   => $now,
                    'login_ip'     => $this->request->ip(),
                    'created_at'   => $now,
                    'nickname'     => $params['nickname'] ?? '',
                    'headimgurl'   => $params['headimgurl'] ?? '',
                    'mobile'       => $params['mobile'] ?? '',
                    'status'       => AccountRepository::STATUS_NORMAL,
                    'is_active'    => $isActive,
                    'phone_active' => $phoneActive,
                    'session_key'  => $wxUser['session_key'] ?? '',
                ]);
            } else {
                $updateData = [
                    'last_login'  => date('Y-m-d H:i:s'),
                    'login_ip'    => $this->request->ip(),
                    'session_key' => $wxUser['session_key'] ?? '',
                ];

                // 更新资料
                $modifyStringList = ['headimgurl', 'nickname', 'mobile'];
                foreach ($modifyStringList as $modifyKey) {
                    if (isset($account[$modifyKey]) && empty($account[$modifyKey])) {
                        $updateData[$modifyKey] = $params[$modifyKey] ?? '';
                    }
                }
                if (empty($account['gender'])) {
                    $updateData['gender'] = $params['gender'] ?? 0;
                }
                if (isset($account['is_active']) && $account['is_active'] == AccountRepository::BOOL_FALSE) {
                    $updateData['is_active'] = $isActive;
                }
                if (isset($account['phone_active']) && $account['phone_active'] == AccountRepository::BOOL_FALSE) {
                    $updateData['phone_active'] = $phoneActive;
                }

                $repo->update($updateData, ['id' => $account['id']]);

                $account = $repo->findById($account['id']);
            }
        } catch (RepositoryException | Exception $e) {
            return $this->json(4003, '登录失败!'.$e->getMessage());
        }

        $account = $account->toArray();
        $jwtData = [
            'user_id'     => $account['id'],
            'open_id'     => $openID,
            'session_key' => $wxUser['session_key'],
            'expire_time' => $wxUser['expire_time'],
        ];

        $account['headimgurl'] = File::convertCompleteFileUrl($account['headimgurl']);
        $fields                = [
            'coding', 'real_name', 'nickname', 'headimgurl', 'gender', 'mobile',
            'status', 'is_active', 'phone_active'
        ];

        $accountData = arrayKeysFilter($account, $fields);
        $data        = [
            'account_id' => $account['id'],
            'token'      => Jwt::generate($jwtData),
            'expire'     => $wxUser['expire_time'],
            'openid'     => $openID,
        ];
        $data        = array_merge($data, $accountData);

        return $this->json(0, 'success', $data);
    }


    /**
     * 获取用户信息
     *
     * @return Json
     */
    public function info(): Json
    {
        try {
            $accountId = $this->request->user['user_id'] ?? 0;

            $user = Account::getUser($accountId);

            return $this->json(0, 'success', $user);
        } catch (Exception $e) {
            return $this->json(4000, '没有相关的用户记录'.$e->getMessage());
        }
    }

    /**
     * 修改用户信息
     */
    public function updateInfo(): Json
    {
        try {
            $params = input('post.');

            $rules = [
                'field|修改项'  => 'require|in:nickname',
                'value|修改内容' => 'require',
            ];

            $accountId = $this->request->user['user_id'] ?? 0;

            $validate = $this->validateByApi($params, $rules, ['field.in' => '参数错误']);

            if ($validate !== true) {
                return $validate;
            }

            if (!$customer = Account::findById($accountId)) {
                return $this->json(4004, '用户不存在');
            }

            $customer->save([
                $params['field'] => $params['value']
            ]);
        } catch (Exception $e) {
            Log::error('修改用户信息失败'.$e->getMessage());
            return $this->json(5000, '修改失败！'.$e->getMessage());
        }

        return $this->json();
    }

    /**
     * 临时登录  通过openid登录 仅用于接口测试阶段
     *
     * @return Json
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function tempLogin(): Json
    {
        $params = $this->request->param();

        if (!isset($params['openid'])) {
            return $this->json(4001, '参数错误');
        }

        if (!$user = AccountRepository::getInstance()->findByOpenID($params['openid'])) {
            return $this->json(4004, '账号不存在');
        }

        $data = [
            'token'  => Jwt::generate(['user_id' => $user['id'], 'nickname' => $user['nickname']]),
            'expire' => Jwt::expire()
        ];

        return $this->json(0, 'success', $data);
    }

    /**
     * 用户操作记录 分享、咨询
     *
     * @return Json
     * @throws Exception
     */
    public function record(): Json
    {
        if (!$this->request->isPost()) {
            return $this->json(4000, '无效请求');
        }

        $accountId = $this->request->user['user_id'] ?? 0;
        $params    = input('post.');

        $rules = [
            'type|操作类型' => 'require|in:content,other,spu,activity',
            'action|操作' => 'require',
        ];

        if (isset($params['type']) && $params['type'] == AccountRecord::TYPE_CONTENT) {
            $rules['id|ID'] = 'require';
        }

        $validate = $this->validateByApi($params, $rules, ['type.in' => '类型错误', 'id.require' => '此类型 ID必传']);

        if ($validate !== true) {
            return $validate;
        }

        try {
            $relationId = $params['id'] ?? 0;
            $relationId = is_numeric($relationId) ? $relationId : 0;
            AccountRecord::record($accountId, $params['type'], $params['action'], $relationId);
        } catch (Exception $e) {
            AccountRepository::log('记录用户操作失败', $e);
            return $this->json(5001, '操作失败');
        }

        return $this->json();
    }

    /**
     * 绑定手机
     *
     * @return bool|Json
     * @throws Exception
     */
    public function bindPhone()
    {
        if (!$this->request->isPost()) {
            return $this->json(4000, '无效请求');
        }

        $accountId = $this->request->user['user_id'] ?? 0;
        $params    = input('post.');

        $rules = [
            'encryptedData|加密数据' => 'require',
            'iv|IV'              => 'require',
        ];

        $validate = $this->validateByApi($params, $rules);

        if ($validate !== true) {
            return $validate;
        }

        try {
            if (!$account = Account::findById($accountId)) {
                return $this->json(4000, '用户不存在');
            }

            // 解密手机相关数据  若存在手机则覆盖
            $minApp      = WechatApplets::getInstance();
            $sessionKey  = $this->request->user['session_key'] ?? '';
            $decryptData = $minApp->encryptor->decryptData($sessionKey, $params['iv'], $params['encryptedData']);
            $phone       = $decryptData['phoneNumber'] ?? ''; // 通过iv和加密数据 解密出手机号

            if (Account::where('id', '<>', $accountId)->where('mobile', $phone)->count() > 0) {
                return $this->json(4000, '该手机已被绑定，若有绑定错误，请联系客服');
            }

            if ($phone) {
                $account->save(['mobile' => $phone, 'phone_active' => Account::COMMON_ON]);
            }

            return $this->json(0, 'success', ['phone' => $phone]);
        } catch (Exception $e) {
            AccountRepository::log('手机绑定失败', $e);
            return $this->json(5001, '手机绑定失败');
        }
    }

    // 打卡页面信息
    public function signInfo(): Json
    {
        $list = [];

        $week    = ['日', '一', '二', '三', '四', '五', '六'];

        $info    = [
            'today' => date('Y年m月d日'),
            'week'  => '星期'.$week[date('w')],
            'now' => date('H:i:s'),
            'is_sign' => (int) !empty($list),
        ];

        return $this->json(0, 'success', ['info' => $info]);
    }

    // 今日打卡记录
    public function signToday(): Json
    {
        $accountId = $this->request->user['user_id'] ?? 0;

        $list = [];

        if ($accountId > 0) {
            $where   = [];
            $where[] = ['cl.created_at', '>', date('Y-m-d 00:00:00')];
            $where[] = ['cl.created_at', '<', date('Y-m-d 23:59:59')];
            $where[] = ['cl.account_id', '=', $accountId];
            $list    = \app\model\ClockLog::alias('cl')
                ->leftJoin('worksite w', 'w.id = cl.worksite_id')
                ->field('cl.*,w.name as worksite_name')
                ->where($where)
                ->order('cl.id', 'desc')
                ->select();

            $list->each(function ($item) {
                $item->type_text = $item->type == 'in' ? '上班' : '下班';
                switch ($item->status) {
                    case 0:
                        $item->status_text = '待确认';
                        break;
                    case 1:
                        $item->status_text = '已确认';
                        break;
                    case -1:
                        $item->status_text = '不通过';
                        break;
                }
                $item->time = date('H:i:s', $item->create_time);
            });
            $list = $list->toArray();
        }

        return $this->json(0, 'success', ['list' => $list]);
    }

    public function checkActive(): Json
    {
        try {
            $openid = input('openid/s');
            if (empty($openid)) {
                return $this->json(0,'success', ['status' => 0]);
            }

            $isActive = (int)Account::where('openid', $openid)->value('is_active');

            return $this->json(0, 'success', ['status' => $isActive]);
        } catch (Exception $e) {
            return $this->json(4000, '检查账号是否微信授权是不'.$e->getMessage());
        }
    }

    // 月度打卡记录
    public function monthSignLog(): Json
    {
        $accountId = $this->request->user['user_id'] ?? 0;
        $date = input('date/d', date('Y-m'));
        $ym = str_replace('-', '', $date);

        $list = [];

        if ($accountId > 0) {
            $where   = [];

            $where[] = ['cl.day', 'like', $ym.'%'];
            $where[] = ['cl.account_id', '=', $accountId];
            $list    = \app\model\ClockLog::alias('cl')
                ->leftJoin('worksite w', 'w.id = cl.worksite_id')
                ->field('cl.*,w.name as worksite_name')
                ->where($where)
                ->order('cl.id', 'desc')
                ->select();

            $list->each(function ($item) {
                $item->type_text = $item->type == 'in' ? '上班' : '下班';
                switch ($item->status) {
                    case 0:
                        $item->status_text = '待确认';
                        break;
                    case 1:
                        $item->status_text = '已确认';
                        break;
                    case -1:
                        $item->status_text = '不通过';
                        break;
                }
                $item->time = date('H:i:s', $item->create_time);
            });
            $list = $list->toArray();
        }

        return $this->json(0, 'success', ['list' => $list]);
    }
}
