<?php

declare(strict_types=1);

namespace app\common\model\account;

use app\common\model\Base;
use Exception;
use mb\helper\Collection;
use mb\helper\Core;
use think\facade\Db;
use app\common\model\core\Excel;
use think\facade\Log;

/**
 * Class User
 * @package app\common\model\account
 */
class User
{
    public const GENDER = [
        1 => '男',
        2 => '女',
        0 => '未填写',
    ];

    public const ROLE = [
        'root' => '系统管理员',
        'manager' => '管理员',
        'user' => '用户',
    ];

    public const EXPORTHEADER = [
        'uid' => '账号',
        'name' => '姓名',
        'gender' => '性别',
        'birthday' => '出生年月日',
        'department' => '部门',
        'duty' => '职务',
        'company' => '单位',
        'phone' => '电话',
        'cardType' => '证件类型',
        'cardNum' => '证件号码',
        'ip' => '登录IP',
        'role' => '类型',
        'status' => '状态'
    ];

    /**
     * uid 账号
     * name 用户名称
     * password 用户密码
     * salt 盐
     * gender 性别 1 - 男 2 - 女
     * birthday 生日 int
     * avatar 头像
     * department 部门
     * duty 职务
     * phone 手机号
     * card_type 证件类型
     * card_num 证件编号
     * role 权限
     * status 状态
     * founder 创建人
     * privileges 菜单
     * ip 登录IP
     * @param $userInfo
     * @return int|string
     */
    public static function add($userInfo)
    {
        $newRow = Collection::keyStyle($userInfo, Collection::NAME_STYLE_C);
        $newRow = Collection::elements([
            'uid',
            'name',
            'password',
            'gender',
            'birthday',
            'avatar',
            'department',
            'duty',
            'company',
            'phone',
            'card_type',
            'card_num',
            'role',
            'status',
            'founder',
            'privileges',
            'salt',
            'ip',
        ], $newRow);
        $newRow['time_created'] = time();
        $newRow['exam_type'] = '';
        try {
            return Db::table('account_users')
                ->insertGetId($newRow);
        } catch (Exception $e) {
            Log::channel('myError')->write($e->getMessage(), \think\Log::ERROR);
        }
        return 0;
    }

    /**
     * @param $filters
     * @param array $newState
     * @return bool
     */
    public static function update($filters, array $newState)
    {
        $where = self::parseFilters($filters);
        $newState = Collection::keyStyle($newState, Collection::NAME_STYLE_C);
        try {
            $offect = Db::table('account_users')
                ->where($where)
                ->update($newState);
            if (!empty($offect)) {
                return true;
            }
        } catch (Exception $e) {
            Log::channel('myError')->write($e->getMessage(), \think\Log::ERROR);
        }
        return false;
    }

    /**
     * @param $filters
     * @return int
     */
    public static function remove($filters)
    {
        $where = self::parseFilters($filters);
        try {
            return Db::table('account_users')
                ->where($where)
                ->delete();
        } catch (Exception $e) {
            Log::channel('myError')->write($e->getMessage(), \think\Log::ERROR);
        }
        return false;
    }

    /**
     * @param $filters
     * @return array
     */
    public static function fetch($filters)
    {
        $where = self::parseFilters($filters);
        try {
            $userInfo = Db::table('account_users')
                ->where($where)
                ->find();
            if (!empty($userInfo)) {
                $userInfo['privileges'] = @unserialize($userInfo['privileges']);
                if (!is_array($userInfo['privileges'])) {
                    $userInfo['privileges'] = [];
                }
                $userInfo['exam_type'] = @unserialize($userInfo['exam_type']);
                return Collection::keyStyle($userInfo, Collection::NAME_STYLE_JAVA);
            }
        } catch (Exception $e) {
            Log::channel('myError')->write($e->getMessage(), \think\Log::ERROR);
        }
        return [];
    }

    /**
     * userFilters array
     * userFilters.id
     * userFilters.uid
     * userFilters.ids
     * userFilters 为int 等于ID
     * @param $userFilters
     * @return array
     */
    public static function parseFilters($userFilters)
    {
        $filters = [];
        if (is_array($userFilters)) {
            if (!empty($userFilters['id'])) {
                $filters[] = ['id', '=', $userFilters['id']];
            }
            if (!empty($userFilters['uid'])) {
                $filters[] = ['uid', '=', $userFilters['uid']];
            }
            if (!empty($userFilters['ids'])) {
                $filters[] = ['id', 'in', $userFilters['ids']];
            }
            if (empty($userFilters)) {
                throw error(-10, '缺少参数,必须指定id,uid,ids');
            }
            if (!empty($userFilters['founder'])) {
                $filters[] = ['founder', '=', $userFilters['founder']];
            }
        } else {
            $filters[] = ['id', '=', intval($userFilters)];
        }
        return $filters;
    }

    /**
     * filters.id id
     * filters.department 职务
     * filters.duty 部门
     * filters.name 姓名
     * filters.uid 账号
     * filters.role 类型 root 系统管理员 manager 管理员 user 用户
     * filters.status 状态 normal - 正常 error - 禁用
     * filters.timeCreatedMax 创建最大时间
     * filters.timeCreatedMin 创建最小时间
     * filters.order array 例:['id' => 'desc'] 排序
     * @param array $filters
     * @param int $pIndex
     * @param int $pSize
     * @param int $total
     * @return array
     */
    public static function search(array $filters, int $pIndex = 0, int $pSize = 10, &$total = 0)
    {
        $where = [];
        $whereOr = [];
        if (!empty($filters['id'])) {
            $where[] = ['id', '=', $filters['id']];
        }
        $whereOr[] = ['id','>','1'];
        if (!empty($filters['minUid'])) {
            $where[] = ['uid','>=',$filters['minUid']];
        }
        if (!empty($filters['maxUid'])) {
            $where[] = ['uid','<=',$filters['maxUid']];
        }
        if (!empty($filters['department'])) {
            $where[] = ['department', '=', $filters['department']];
        }
        if (!empty($filters['duty'])) {
            $where[] = ['duty', '=', $filters['duty']];
        }
        if (!empty($filters['uid'])) {
            $where[] = ['uid', 'like', "%{$filters['uid']}%"];
        }
        if (!empty($filters['name'])) {
            $where[] = ['name', 'like', '%' . $filters['name'] . '%'];
        }
        if (!empty($filters['role'])) {
            $where[] = ['role', '=', $filters['role']];
        }
        if (!empty($filters['founder'])) {
            $where[] = ['founder', '=', $filters['founder']];
        }
        if (!empty($filters['status'])) {
            $where[] = ['status', '=', $filters['status']];
        }
        if (!empty($filters['timeCreatedMax'])) {
            $where[] = ['time_created', '<=', $filters['timeCreatedMax']];
        }
        if (!empty($filters['timeCreatedMin'])) {
            $where[] = ['time_created', '>=', $filters['timeCreatedMin']];
        }
        if (!empty($filters['ids'])) {
            $where[] = ['id', 'in', "{$filters['ids']}"];
        }
        try {
            $total = Db::table('account_users')
                ->where($where)
                ->count();
            $query = Db::table('account_users')
                ->where($where);
            if (!empty($pIndex)) {
                $query->page($pIndex, $pSize);
            }
            if (!empty($filters['order'])) {
                $query->order($filters['order']);
            }
            $dataSet = $query->select()->toArray();
            if (!empty($dataSet)) {
                return array_map(function ($row) {
                    $row['privileges'] = @unserialize($row['privileges']);
                    $row['exam_type'] = @unserialize($row['exam_type']);
                    unset($row['password']);
                    unset($row['salt']);
                    return Collection::keyStyle($row, Collection::NAME_STYLE_JAVA);
                }, $dataSet);
            }
        } catch (Exception $e) {
            Log::channel('myError')->write($e->getMessage(), \think\Log::ERROR);
        }
        return [];
    }

    /**
     * @param array $filters
     * @param array $data
     * @return bool
     */
    public static function addMarkExaminationPapers(array $filters, array $data)
    {
        $arr = [
            'paramId' => $filters['id'],
            'department' => $data['department'],
            'user' => $data['user']
        ];
        $res = Base::watch('mark_examination_papers', $arr);
        if (is_error($res)) {
            return false;
        }
        return true;
    }

    /**
     * 返回评卷账号
     * @param int $accountID
     * @return array|string
     * array.department
     * array.user
     */
    public static function getMarkExaminationPapers(int $accountID)
    {
        $where = [];
        $where[] = ['account', '=', $accountID];
        $retrunSet = [];
        try {
            $dataSet = Db::table('account_mark_examination_papers')
                ->where($where)
                ->select();
            foreach ($dataSet as $v) {
                if ($v['type'] == 'department') {
                    $retrunSet[$v['type']][] = $v['binding_id'];
                } elseif ($v['type'] == 'user') {
                    $user = self::fetch(intval($v['binding_id']));
                    if (!empty($user)) {
                        $department = Department::fetch(intval($user['department']));
                    }
                    $retrunSet[$v['type']][] = [
                        'id' => $user['id'],
                        'name' => $user['name'],
                        'departmentTitle' => $department['title'],
                        'department' => $department['id'],
                        'uid' => $user['uid'],
                    ];
                }
            }
        } catch (Exception $e) {
            Log::channel('myError')->write($e->getMessage(), \think\Log::ERROR);
        }
        return empty($retrunSet) ? '' : $retrunSet;
    }

    /**
     * 导出账户信息
     * @param $filters
     * @param $headers
     */
    public static function export($filters, $headers)
    {
        $userSet = self::search($filters, 0);
        $department = Department::search([], 0);
        $dutySet = Duty::search([], 0);
        $department = Base::headelId('id', $department);
        $dutySet = Base::headelId('id', $dutySet);
        $basic = self::EXPORTHEADER;
        $headerTitle = [''];
        $headerTitle = array_merge($headerTitle, array_map(function ($val) use ($basic) {
            return $basic[$val];
        }, $headers));
        $excelSet = [];
        foreach ($userSet as $v) {
            $tmp = ['' => ''];
            foreach ($headers as $h) {
                switch ($h) {
                    case 'gender':
                        $tmp[$h] = !empty(self::GENDER[$v[$h]]) ? self::GENDER[$v[$h]] : '';
                        break;
                    case 'birthday':
                        $tmp[$h] = !empty($v['birthday']) ? date('Y-m-d', $v['birthday']) : '';
                        break;
                    case 'department':
                        $tmp[$h] = !empty($department[$v['department']]) ? $department[$v['department']]['title'] : '';
                        break;
                    case 'duty':
                        $tmp[$h] = !empty($dutySet[$v['duty']]) ? $dutySet[$v['duty']]['title'] : '';
                        break;
                    case 'role':
                        $tmp[$h] = !empty(self::ROLE[$v['role']]) ? self::ROLE[$v['role']] : '';
                        break;
                    case 'status':
                        $tmp[$h] = ($v['status'] == 'normal') ? '正常' : '禁用';
                        break;
                    default:
                        $tmp[$h] = $v[$h];
                        break;
                }
            }
            $excelSet[] = $tmp;
        }
        Excel::write('账号列表', $headerTitle, $excelSet);
        exit;
    }

    public static function import($excelUrl)
    {
        $error = [];
        $currentUser = \app\control\model\User::fetchCurrent();
        $genders = Base::exchangeKey(self::GENDER);
        $roles = Base::exchangeKey(self::ROLE);
        $departments = Department::search([], 0);
        $departments = Base::headelId('title', $departments);
        $dutys = Duty::search([], 0);
        $dutys = Base::headelId('title', $dutys);
        $users = Excel::read($excelUrl, [
            ['field' => 'uid', 'column' => 'A'],
            ['field' => 'name', 'column' => 'B'],
            ['field' => 'password', 'column' => 'C'],
            ['field' => 'gender', 'column' => 'D'],
            ['field' => 'birthday', 'column' => 'E'],
            ['field' => 'department', 'column' => 'F'],
            ['field' => 'duty', 'column' => 'G'],
            ['field' => 'company', 'column' => 'H'],
            ['field' => 'phone', 'column' => 'I'],
            ['field' => 'cardType', 'column' => 'J'],
            ['field' => 'cardNum', 'column' => 'K'],
            ['field' => 'role', 'column' => 'L'],
            ['field' => 'status', 'column' => 'M'],
        ]);
        if (is_error($users) || empty($users)) {
            return error(-23, '文件错误');
        }
        $line = 1;
        foreach ($users as $v) {
            $line++;
            if (is_object($v)) {
                $error[$line] = ['line' => $line, 'msg' => '模板格式有误'];
                continue;
            }
            $params = [];
            $exists = self::fetch(['uid' => $v['uid']]);
            if (!empty($exists)) {
                $error[$line] = ['line' => $line, 'msg' => '该用户uid：' . $v['uid'] . '存在'];
                continue;
            }
            $params['uid'] = (string)$v['uid'];
            $params['name'] = (string)$v['name'];
            $params['salt'] = Core::random(6);
            $v['password'] = (string)empty($v['password']) ? '123456' : $v['password'];
            $params['password'] = Base::encodePassword($params['salt'], $v['password']);
            $params['gender'] = (string)!empty($genders[$v['gender']]) ? $genders[$v['gender']] : '';
            $params['birthday'] = (string)!empty($v['birthday']) ? strtotime((string)$v['birthday']) : '';
            $params['phone'] = (string)$v['phone'];
            $params['cardType'] = (string)$v['cardType'];
            $params['cardNum'] = (string)$v['cardNum'];
            $params['company'] = (string)$v['company'];
            $params['founder'] = $currentUser['id'];
            $params['status'] = (string)(!empty($v['status']) && $v['status'] == '正常') ? 'normal' : 'error';
            $v['department'] = (string)$v['department'];
            if (empty($departments[$v['department']])) {
                $error[$line] = ['line' => $line, 'msg' => '没有此部门:' . $v['department']];
                continue;
            }
            $department = Department::fetch(['pid' => $departments[$v['department']]['id']]);
            if (!empty($department)) {
                $error[$line] = ['line' => $line, 'msg' => "该({$v['department']})部门不是最下级部门"];
                continue;
            }
            $params['department'] = $departments[$v['department']]['id'];
            if (empty($dutys[$v['duty']])) {
                $params['duty'] = '';
            } else {
                $params['duty'] = $dutys[$v['duty']]['id'];
            }
            if (!in_array($v['role'], self::ROLE)) {
                $error[$line] = ['line' => $line, 'msg' => '没有此账号类型:' . $v['role']];
                continue;
            }
            $params['role'] = $roles[$v['role']];
            if (empty($error[$line])) {
                $result = self::add($params);
                if (!$result) {
                    $error[$line] = ['line' => $line, 'msg' => '添加失败'];
                }
            }
        }
        return $error;
    }
}