<?php

namespace api\controllers;

use api\components\Controller;
use api\models\Freepbx;
use common\web\Identified;
use organize\models\Department;
use organize\models\User;
use organize\services\DepartmentService;
use organize\services\RoleService;
use report\services\CdrService;
use yii\db\Exception;
use yii\db\Query;
use yii\helpers\ArrayHelper;

class ControlController extends Controller
{
    public function rules()
    {
        return [
            'create' => [
                [['domain', 'gateway', 'role'], 'string'],
                [['start', 'end', 'department'], 'integer'],
                [['start', 'end'], 'required']
            ],
            'delete' => [
                [['domain'], 'string'],
                [['start', 'end'], 'integer'],
                [['start', 'end'], 'required']
            ],
            'reset-role' => [
                [['domain', 'role'], 'string'],
                [['start', 'end'], 'integer'],
                [['start', 'end', 'role'], 'required']
            ],
            'reset-password' => [
                [['domain'], 'string'],
                [['start', 'end'], 'integer'],
                [['start', 'end'], 'required']
            ],
            'reset-department' => [
                [['domain'], 'string'],
                [['start', 'end', 'department'], 'integer'],
                [['start', 'end', 'department'], 'required']
            ],
        ];
    }

    public function auth($action)
    {
        $data = User::find()->identified("1000");
        $ts = \Yii::$app->request->get("ts");
        $accessToken = \Yii::$app->request->get("access_token");
        $timestamp = intval($ts);
        if (abs(time() - $timestamp) > 60) {
            return false;
        }
        if (md5($ts . 'a441ru3nfwgRNpfX7Wb96W5CNji5WMUW508r12xLu7T8I7e7V9G4cykPaj8E2irS') == $accessToken) {
            \Yii::$app->user->login(Identified::findIdentity($data));
            return true;
        }
        return parent::auth($action);
    }

    public function dataSource($action)
    {
        if (\Yii::$app->request->headers->get("Content-Type") == "application/json") {
            $data = json_decode(\Yii::$app->request->getRawBody(), true);
            return empty($data) ? [] : $data;
        }
        return \Yii::$app->request->getQueryParams();
    }

    public function getRandomDepartment()
    {
        $query = new Query();
        $id = $query->select('dept_id')->from(Department::tableName())->limit(1)->scalar(Department::getDb());
        if (empty($id)) {
            return 10;
        }
        return $id;
    }

    public function addDevice($no, $password)
    {
        $trans = \Yii::$app->dbAsterisk->beginTransaction();
        try {
            $device = [
                'id' => $no,
                'tech' => 'pjsip',
                'dial' => 'PJSIP/' . $no,
                'devicetype' => 'fixed',
                'user' => $no,
                'description' => '',
                'emergency_cid' => '',
                'hidenum' => '0',
            ];
            $trans->db->createCommand()->insert('devices', $device)->execute();

            $user = [
                'extension' => $no,
                'password' => '',
                'name' => $no,
                'voicemail' => 'novm',
                'ringtimer' => '0',
                'noanswer' => '',
                'recording' => '',
                'outboundcid' => '',
                'sipname' => '',
                'noanswer_cid' => '',
                'busy_cid' => '',
                'chanunavail_cid' => '',
                'noanswer_dest' => '',
                'busy_dest' => '',
                'chanunavail_dest' => '',
                'mohclass' => 'default',
                'trunk' => '',
            ];
            $trans->db->createCommand()->insert('users', $user)->execute();
            $datas = [
                [
                    'keyword' => 'account',
                    'data' => $no,
                    'flags' => '39',
                ],
                [
                    'keyword' => 'accountcode',
                    'data' => '',
                    'flags' => '23',
                ],
                [
                    'keyword' => 'aggregate_mwi',
                    'data' => 'yes',
                    'flags' => '30',
                ],
                [
                    'keyword' => 'allow',
                    'data' => '',
                    'flags' => '21',
                ],
                [
                    'keyword' => 'avpf',
                    'data' => 'no',
                    'flags' => '18',
                ],
                [
                    'keyword' => 'callerid',
                    'data' => 'device <' . $no . '>',
                    'flags' => '40',
                ],
                [
                    'keyword' => 'context',
                    'data' => 'from-internal',
                    'flags' => '12',
                ],
                [
                    'keyword' => 'device_state_busy_at',
                    'data' => '0',
                    'flags' => '34',
                ],
                [
                    'keyword' => 'dial',
                    'data' => 'PJSIP/' . $no,
                    'flags' => '22',
                ],
                [
                    'keyword' => 'dialout_feedback',
                    'data' => 'no',
                    'flags' => '5',
                ],
                [
                    'keyword' => 'disallow',
                    'data' => '',
                    'flags' => '20',
                ],
                [
                    'keyword' => 'dtmfmode',
                    'data' => 'rfc2833',
                    'flags' => '11',
                ],
                [
                    'keyword' => 'forbid_callout',
                    'data' => '0',
                    'flags' => '4',
                ],
                [
                    'keyword' => 'force_rport',
                    'data' => 'yes',
                    'flags' => '28',
                ],
                [
                    'keyword' => 'hidenum',
                    'data' => '0',
                    'flags' => '3',
                ],
                [
                    'keyword' => 'icesupport',
                    'data' => 'no',
                    'flags' => '19',
                ],
                [
                    'keyword' => 'match',
                    'data' => '',
                    'flags' => '35',
                ],
                [
                    'keyword' => 'maximum_expiration',
                    'data' => '7200',
                    'flags' => '36',
                ],
                [
                    'keyword' => 'max_contacts',
                    'data' => '1',
                    'flags' => '24',
                ],
                [
                    'keyword' => 'mediaencryption',
                    'data' => 'no',
                    'flags' => '31',
                ],
                [
                    'keyword' => 'mediaencryptionoptimistic',
                    'data' => 'no',
                    'flags' => '33',
                ],
                [
                    'keyword' => 'media_use_received_transport',
                    'data' => 'no',
                    'flags' => '25',
                ],
                [
                    'keyword' => 'minimum_expiration',
                    'data' => '60',
                    'flags' => '37',
                ],
                [
                    'keyword' => 'mwi_subscription',
                    'data' => 'solicited',
                    'flags' => '29',
                ],
                [
                    'keyword' => 'namedcallgroup',
                    'data' => '1',
                    'flags' => '6',
                ],
                [
                    'keyword' => 'namedpickupgroup',
                    'data' => '1',
                    'flags' => '7',
                ],
                [
                    'keyword' => 'outbound_proxy',
                    'data' => '',
                    'flags' => '38',
                ],
                [
                    'keyword' => 'qualifyfreq',
                    'data' => '60',
                    'flags' => '16',
                ],
                [
                    'keyword' => 'rewrite_contact',
                    'data' => 'yes',
                    'flags' => '27',
                ],
                [
                    'keyword' => 'rtp_symmetric',
                    'data' => 'yes',
                    'flags' => '26',
                ],
                [
                    'keyword' => 'secret',
                    'data' => $password,
                    'flags' => '2',
                ],
                [
                    'keyword' => 'secret_origional',
                    'data' => $password,
                    'flags' => '8',
                ],
                [
                    'keyword' => 'sendrpid',
                    'data' => 'pai',
                    'flags' => '14',
                ],
                [
                    'keyword' => 'sessiontimers',
                    'data' => 'accept',
                    'flags' => '15',
                ],
                [
                    'keyword' => 'sipdriver',
                    'data' => 'chan_pjsip',
                    'flags' => '9',
                ],
                [
                    'keyword' => 'timers',
                    'data' => 'yes',
                    'flags' => '32',
                ],
                [
                    'keyword' => 'transport',
                    'data' => 'Auto',
                    'flags' => '17',
                ],
                [
                    'keyword' => 'trustrpid',
                    'data' => 'yes',
                    'flags' => '13',
                ],
            ];
            foreach ($datas as $k => $v) {
                $v['id'] = $no;
                $trans->db->createCommand()->insert('sip', $v)->execute();
            }
            $trans->commit();
            return true;
        } catch (\Exception $e) {
            \Yii::error("insert device error: " . $e->getMessage());
            $trans->rollBack();
        }
        return false;
    }

    public function delDevice($no)
    {
        $trans = \Yii::$app->dbAsterisk->beginTransaction();
        try {
            $trans->db->createCommand()->delete('devices', ['id' => $no])->execute();
            $trans->db->createCommand()->delete('users', ['extension' => $no])->execute();
            $trans->db->createCommand()->delete('sip', ['id' => $no])->execute();
            $trans->commit();
            return true;
        } catch (\Exception $e) {
            \Yii::error("delete device error: " . $e->getMessage());
            $trans->rollBack();
        }
        return false;
    }

    public function actionCreate()
    {
        $failureList = [];
        set_time_limit(120);
        $data = $this->attributes();
        $start = intval(ArrayHelper::getValue($data, 'start'));
        $end = intval(ArrayHelper::getValue($data, 'end'));
        $domain = ArrayHelper::getValue($data, 'domain');
        if ($start > $end) {
            return $this->error(4001, '起码号码必须小于结束号码');
        }
        if (empty($data['department']) || !isset($data['department'])) {
            $data['department'] = $this->getRandomDepartment();
        }

        if (empty($data['domain'])) {
            $data['domain'] = ArrayHelper::getValue($_ENV, 'BRANCH_CODE');
        }

        if (empty($data['role'])) {
            $data['role'] = 'admin';
        }

        for ($i = $start; $i <= $end; $i++) {
            $pwd = strtoupper($domain) . 'pwd#' . $i;
            if (!$this->addDevice($i . '', $pwd)) {
                $failureList[] = $i;
                continue;
            }
            usleep(50);
            $model = new \organize\models\complex\User();
            $model->agent_number = $i . '';
            $model->username = strtoupper($domain) . $i;
            $model->nickname = $model->username;
            $model->realname = $model->username;
            $model->password = \Yii::$app->security->generatePasswordHash(md5($pwd));
            $model->confirm_password = $model->password;
            $model->dept_id = ArrayHelper::getValue($data, 'department') . '';
            $model->role = ArrayHelper::getValue($data, 'role');
            $model->device = $i . '';
            if (!$model->save()) {
                $failureList[] = $i;
            }
            usleep(250);
        }
        return [
            'failure' => $failureList
        ];
    }

    public function actionDelete()
    {
        $failureList = [];
        $data = $this->attributes();
        $start = intval(ArrayHelper::getValue($data, 'start'));
        $end = intval(ArrayHelper::getValue($data, 'end'));
        $domain = ArrayHelper::getValue($data, 'domain');
        if ($start > $end) {
            return $this->error(4001, '起码号码必须小于结束号码');
        }
        for ($i = $start; $i <= $end; $i++) {
            $model = User::findOne(['agent_number' => $i . '']);
            if (!empty($model)) {
                if (!empty($model->device)) {
                    if (!$this->delDevice($model->device)) {
                        $failureList[] = $i;
                        continue;
                    }
                }
                $model->delete();
            }
        }
        return [
            'failure' => $failureList
        ];
    }

    public function actionUsers()
    {
        $data = (new Query())->select('username,agent_number,device,dept_id,is_delete')->from(User::tableName())->all(User::getDb());
        return $data;
    }

    public function actionDepartments()
    {
        return DepartmentService::recursiveMap();
    }

    public function actionRoles()
    {
        return RoleService::getMap();
    }

    public function actionGateways()
    {
        return CdrService::getTrunkMap();
    }

    public function actionStatus()
    {
        $table = CdrService::getTableByCallId(time(), CdrService::TABLE_TYPE_MERGE);
        $query = (new Query());
        $data = $query->select('call_type,count(*)')->from($table)->where([
            ['>', 'link_stamp', strtotime(time(), "YYYY-MM-DD") . " 00:00:00"],
            ['<', 'link_stamp', strtotime(time(), "YYYY-MM-DD") . " 23:59:59"]
        ])->groupBy('call_type')->all(\Yii::$app->dbAsteriskCdrdb);
        return $data;
    }

    public function actionResetPassword()
    {
        $failureList = [];
        $data = $this->attributes();
        $start = intval(ArrayHelper::getValue($data, 'start'));
        $end = intval(ArrayHelper::getValue($data, 'end'));
        $domain = ArrayHelper::getValue($data, 'domain');
        if ($start > $end) {
            return $this->error(4001, '起码号码必须小于结束号码');
        }
        for ($i = $start; $i <= $end; $i++) {
            $model = (new Query())
                ->select('username')
                ->from(\organize\models\complex\User::tableName())
                ->where(['agent_number' => $i])
                ->one(User::getDb());
            if (empty($model)) {
                $failureList[] = $i;
                continue;
            }
            $username = $model['username'];
            $pos = strpos($username, $i . '');
            if ($pos === false) {
                $failureList[] = $i;
                continue;
            }
            $password = substr($username, 0, $pos) . 'pwd#' . $i;
            User::getDb()
                ->createCommand()
                ->update(
                    User::tableName(),
                    ['password' => \Yii::$app->security->generatePasswordHash(md5($password))],
                    ['agent_number' => $i])
                ->execute();
        }
        return [
            'failure' => $failureList
        ];
    }

    public function actionResetRole()
    {
        $failureList = [];
        $data = $this->attributes();
        $start = intval(ArrayHelper::getValue($data, 'start'));
        $end = intval(ArrayHelper::getValue($data, 'end'));
        $role = ArrayHelper::getValue($data, 'role');
        if ($start > $end) {
            return $this->error(4001, '起码号码必须小于结束号码');
        }
        for ($i = $start; $i <= $end; $i++) {
            $model = \organize\models\complex\User::findOne(['agent_number' => $i . '']);
            if (!empty($model)) {
                $model->role = $role;
                if (!$model->save(false)) {
                    $failureList[] = $i;
                }
            } else {
                $failureList[] = $i;
            }
        }
        return [
            'failure' => $failureList
        ];
    }

    public function actionResetDepartment()
    {
        $failureList = [];
        $data = $this->attributes();
        $start = intval(ArrayHelper::getValue($data, 'start'));
        $end = intval(ArrayHelper::getValue($data, 'end'));
        $department = ArrayHelper::getValue($data, 'department');
        if ($start > $end) {
            return $this->error(4001, '起码号码必须小于结束号码');
        }
        for ($i = $start; $i <= $end; $i++) {
            $model = \organize\models\complex\User::findOne(['agent_number' => $i . '']);
            if (!empty($model)) {
                $model->dept_id = $department;
                if (!$model->save(false)) {
                    $failureList[] = $i;
                }
            } else {
                $failureList[] = $i;
            }
        }
        return [
            'failure' => $failureList
        ];
    }

    public function actionResetGateway()
    {
        $failureList = [];
        $data = $this->attributes();
        $start = intval(ArrayHelper::getValue($data, 'start'));
        $end = intval(ArrayHelper::getValue($data, 'end'));
        $gateway = ArrayHelper::getValue($data, 'gateway');
        if ($start > $end) {
            return $this->error(4001, '起码号码必须小于结束号码');
        }
        for ($i = $start; $i <= $end; $i++) {
            try {
                \Yii::$app->dbAsterisk->createCommand()->update('users', ['trunk' => $gateway, 'outboundcid' => $gateway], ['extension' => $i . ''])->execute();
            } catch (Exception $e) {
                \Yii::error("reset gateway error: " . $e->getMessage());
                $failureList[] = $i;
            }
        }
        return [
            'failure' => $failureList
        ];
    }

    public function actionReload()
    {
        $freepbx = new Freepbx();
        $arrResult = $freepbx->reload();
        if (0 == $arrResult['code']) {
            return $arrResult['message'];
        } else {
            return $this->error(505, $arrResult['message']);
        }
    }
}