<?php

namespace Api\PhpServices\Certification;

use Api\PhpUtils\Http\Request;

class IdCertification
{
    private const key                   = '32f9XIsReV4S15Ck_Sa3ky43XgAHUB9v';
    private const secret                = 'usZbQYdI4PQeXhMftsRfHK2msj0DmSIl';
    private const kuangshi_ocr_url      = 'https://api.megvii.com/faceid/v3/ocridcard';
    private const kuangshi_get_token    = 'https://api.megvii.com/faceid/v3/sdk/get_biz_token';
    private const kuangshi_face_compare = 'https://api.megvii.com/faceid/v3/sdk/verify';

    /**
     * 身份证合法校验
     * @param $id_number
     * @return bool
     */
    public static function checkIdcard (string $id_number) :bool
    {
        $weight   = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
        $codes    = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];

        if (strlen($id_number) !== 18) {
            return false;
        }

        $validate = substr($id_number, 0, 17);
        $sum = 0;
        for ($i = 0; $i < 17; $i++) {
            $sum += $validate[$i] * $weight[$i];
        }

        return $codes[$sum % 11] === $id_number[17];
    }

    /**
     * 获取sign
     * @param $api_key
     * @param $api_secret
     * @param $expired
     * @file https://faceid.com/pages/documents/37662604
     * @return string
     */
    private static function genSign($api_key, $api_secret, $expired) :string
    {
        $rdm = rand();
        $current_time = time();
        $expired_time = $current_time + $expired;
        $srcStr = "a=%s&b=%d&c=%d&d=%d";
        $srcStr = sprintf($srcStr, $api_key, $expired_time, $current_time, $rdm);
        return base64_encode(hash_hmac('SHA1', $srcStr, $api_secret, true).$srcStr);
    }

    /**
     * 身份证ocr
     * @param $posit_image_url string 身份证人头像图片地址
     * @param $back_image_url string  身份证国徽像图片地址
     * @file https://faceid.com/pages/documents/10881005
     * @return array
     */
    public function idCardOcr($posit_image_url,$back_image_url) :array
    {
        if (!empty($posit_image_url)) {
            $result_posit = $this->getIdCardOcr($posit_image_url);
        }
        if (!empty($back_image_url)) {
            $result_back = $this->getIdCardOcr($back_image_url);
        }
        $final['posit'] = self::analysisPositData($result_posit ?? []);
        $final['back'] = self::analysisBackData($result_back ?? []);
        return $final;
    }

    /**
     * 单次获取 ocr
     * @param $image_url
     * @param $return_portrait int 设定是否返回身份证上的人像 “0”：不返回 | “1”：返回人像
     * @file https://faceid.com/pages/documents/10881005
     * @return array
     */
    public function getIdCardOcr($image_url,$return_portrait=1)
    {
        $get = ['api_key' => self::key,'api_secret'=> self::secret, 'return_portrait' => $return_portrait];
        $url = self::kuangshi_ocr_url. '?' . http_build_query($get);
        $form_data = [
            ['name' => 'image' , 'contents' => $this->getFile($image_url)]
        ];
        return (new Request())->post($url, $form_data, 3000, 'multipart',[],1);
    }

    /**
     * 并发请求 身份证ocr
     * @param $posit_image_url
     * @param $back_image_url
     * @return mixed
     */
    public function mgetIdCardOcr($posit_image_url,$back_image_url)
    {
        $posit_image_url = $this->getFile($posit_image_url);
        $form_data1 = [
            ['name' => 'api_key', 'contents' => self::key],
            ['name' => 'api_secret', 'contents' => self::secret],
            ['name' => 'image' , 'contents' => fopen($posit_image_url,'r')]
        ];
        $form_data2 = [
            ['name' => 'api_key', 'contents' => self::key],
            ['name' => 'api_secret', 'contents' => self::secret],
            ['name' => 'image' , 'contents' => fopen($back_image_url,'r')]
        ];

        $urls = [
            0 => self::kuangshi_ocr_url,
            1 => self::kuangshi_ocr_url,
        ];
        $params = [
            0 => $form_data1,
            1 => $form_data2,
        ];
        $timeouts = [
            0 => 5000,
            1 => 5000
        ];
        $content_types = [
            0 => 'multipart',
            1 => 'multipart'
        ];

        $result = (new Request())->concurrencyPost($urls,$params , $timeouts, $content_types);

        $final['posit'] = self::analysisPositData($result[0]);
        $final['back'] = self::analysisBackData($result[1]);

        return $final;
    }

    /**
     * 获取 活体检测token
     * @param $id_number      string 身份证号
     * @param $id_card_name   string 姓名
     * @param $liveness_type  string 检测方式 （"still"(静默) / ”meglive”(动作活体)/  ”flash”(炫彩活体)）
     * @param $biz_no         string 业务号
     * @param $expired        int    签名生效时长 ，单位秒
     * @file  https://faceid.com/pages/documents/37661898
     * @return string
     */
    public function getBizToken($id_number,$id_card_name,$liveness_type='meglive',$biz_no='merchat',$expired=10) :string
    {
        $form_data = [
            ['name' => 'sign', 'contents' => self::genSign(self::key,self::secret,$expired)],
            ['name' => 'sign_version', 'contents' => 'hmac_sha1'],
            ['name' => 'liveness_type', 'contents' => $liveness_type],
            ['name' => 'comparison_type', 'contents' => '1'],
            ['name' => 'idcard_name', 'contents' => $id_card_name],
            ['name' => 'idcard_number', 'contents' => $id_number],
            ['name' => 'biz_no', 'contents' => $biz_no],
            ['name' => 'verbose','contents' => '1'],
            ['name' => 'get_liveness_video', 'contents' => '1']
        ];

        $result = (new Request())->post(self::kuangshi_get_token, $form_data, 1500, 'multipart');
        if (isset($result['code'],$result['response']['biz_token']) && $result['code'] === 0) {
            return $result['response']['biz_token'];
        }
        return '';
    }

    /**
     * 人脸比对接口
     * @param $biz_token
     * @param $meglive_data_url
     * @param int $expired
     * @file https://faceid.com/pages/documents/37662519
     * @return array|mixed
     */
    public function verify($biz_token,$meglive_data_url,$expired=10)
    {
        $form_data = [
            ['name' => 'sign' , 'contents' => self::genSign(self::key,self::secret,$expired)],
            ['name' => 'sign_version', 'contents' => 'hmac_sha1'],
            ['name' => 'biz_token', 'contents' => $biz_token],
            ['name' => 'meglive_data', 'contents' => $this->getFile($meglive_data_url)]
        ];

        $result = (new Request())->post(self::kuangshi_face_compare, $form_data, 3000, 'multipart',[],1);
        if (isset($result['code'], $result['response']) && $result['code'] === 0) {
            return $result['response'];
        }
        return $result['msg']?? '活体检测失败';
    }

    /**
     * 返回文件句柄
     * @param $file
     * @return bool|false|string
     */
    private function getFile($file)
    {
        if (strpos($file, 'http') === false && !file_exists($file)) {
            return false;
        }
        //获取文件内容
        $file_content = fopen($file,'r');
        if ($file_content === false) {
            return false;
        }
        return $file_content;
    }

    /**
     * 解析人头像 数据
     * @param $ocr_data
     * @return array
     */
    private static function analysisPositData($ocr_data)
    {
        $final_data['name'] = $ocr_data['response']['name']['result'] ?? '';
        $final_data['gender'] = $ocr_data['response']['gender']['result'] ?? '';
        $final_data['address'] = $ocr_data['response']['address']['result'] ?? '';
        $final_data['idcard_number'] = $ocr_data['response']['idcard_number']['result'] ?? '';
        $final_data['birth_month'] = $ocr_data['response']['birth_month']['result'] ?? '';
        $final_data['birth_day'] = $ocr_data['response']['birth_day']['result'] ?? '';
        $final_data['nationality'] = $ocr_data['response']['nationality']['result'] ?? '';
        $final_data['birth_year'] = $ocr_data['response']['birth_year']['result'] ?? '';
        $final_data['completeness'] = $ocr_data['response']['completeness'] ?? -1;
        $final_data['legality'] = $ocr_data['response']['legality'] ?? (object)[];
        return $final_data;
    }

    /**
     * 解析国徽面数据
     * @param $ocr_data
     * @return array
     */
    private static function analysisBackData($ocr_data)
    {
        $final_data['valid_date_start'] = $ocr_data['response']['valid_date_start']['result'] ?? '';
        $final_data['issued_by'] = $ocr_data['response']['issued_by']['result'] ?? '';
        $final_data['valid_date_end'] = $ocr_data['response']['valid_date_end']['result'] ?? '';
        $final_data['completeness'] = $ocr_data['response']['completeness'] ?? -1;
        $final_data['legality'] = $ocr_data['response']['legality'] ?? (object)[];
        return $final_data;
    }
}