<?php

namespace Extend\Ca;

use App\Constants\HttpEnumCode;
use App\Exception\BusinessException;
use App\Utils\Log;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Snowflake\IdGeneratorInterface;
use Hyperf\Utils\ApplicationContext;
use Psr\Container\ContainerInterface;

/**
 * 四川ca云证书+电子签章
 */
class Ca
{
    #[Inject]
    protected ContainerInterface $container;

    #[Inject]
    protected Client $client;

    public function __construct()
    {
        $this->container = ApplicationContext::getContainer();
        $this->client = $this->container->get(Client::class);
    }

    /**
     * 获取云证书
     * @param array $data
     * @return mixed
     */
    public function getCloudCert(array $data): mixed
    {
        $option = [
            'form_params' => [
                'entityId' => $data['user_id'], // 用户唯一标识，由业务系统定义
                'entityType' => "Personal",// 用户类型，可选值[Personal/Organizational]
                'pin' => $data['user_id'], // 证书PIN码
                'cardNumber' => $data['card_num'], // 证件号码(个人身份证;企业统一社会信用代码)
            ]
        ];

        try {
            $response = $this->httpRequest(config("ca.api_url") . '/cloud-certificate-service' . '/api/cloudCert/open/v2/cert/offlineAuthCertEnroll', $option);
            if (empty($response)) {
                // 返回值为空
                throw new BusinessException(HttpEnumCode::getMessage(HttpEnumCode::SERVER_ERROR));
            }
            return $response;
        } catch (GuzzleException $e) {
            throw new BusinessException($e->getMessage());
        }
    }

    /**
     * 获取云证书签名
     * @param string $user_id
     * @param string $pin
     * @param array $data
     * @return mixed
     */
    public function getCertSign(string $user_id, string $pin, array $data): mixed
    {
        $option = [
            'form_params' => [
                'entityId' => $user_id, // 用户唯一标识，由业务系统定义
                'toSign' => hash_hmac("sha1", json_encode($data, JSON_UNESCAPED_UNICODE), config("ca.secret")), // 签名原文
                'pin' => $pin, // 证书PIN码
            ]
        ];

        try {
            $response = $this->httpRequest(
                config("ca.api_url") . '/cloud-certificate-service' . '/api/cloudCert/open/cert/sign',
                $option
            );
            if (empty($response)) {
                // 返回值为空
                throw new BusinessException(HttpEnumCode::getMessage(HttpEnumCode::SERVER_ERROR));
            }
            return $response;
        } catch (GuzzleException $e) {
            throw new BusinessException($e->getMessage());
        }
    }

    // PKCS7签名验证接口
    // 对客户端签名信息进行验证，返回证书信息，同时可以配置回调服务，在验证成功后回调业务系统
    public function verifyPkcs7(string $sign_p7, array $data)
    {
        $generator = $this->container->get(IdGeneratorInterface::class);

        $option = [
            'form_params' => [
                'opType' => "签名验证",
                'requestId' => $generator->generate(),// 业务流水号，唯一
                'signedData' => $sign_p7, // 签名值：签名接口返回的signP7
                'toSign' => hash_hmac("sha1", json_encode($data, JSON_UNESCAPED_UNICODE), config("ca.secret")), // 签名原文
            ]
        ];

        try {
            $response = $this->httpRequest(
                config("ca.api_url") . '/signgw-service/api/signature/verifyPkcs7',
                $option
            );
            if (empty($response)) {
                // 返回值为空
                throw new BusinessException(HttpEnumCode::getMessage(HttpEnumCode::SERVER_ERROR));
            }
            return $response;
        } catch (GuzzleException $e) {
            throw new BusinessException($e->getMessage());
        }
    }

    /**
     * 添加签章配置
     * @param string $user_id 用户id
     * @param string $card_num 身份证号
     * @param array $data
     * @return mixed
     */
    public function addUserSignConfig(string $user_id, string $card_num, array $data): mixed
    {
        $option = [
            'form_params' => [
                'userId' => $user_id,//用户标识信息（为云证书entityId）
                'configKey' => $user_id, // 签章配置唯一标识，一张云证书配置一个
                'keypairType' => "3", // 秘钥类型(3云证书)
                'certSn' => $card_num, // 证书序列号，使用医生身份证号即可
                'signType' => "4", // 签章方式(签章类型; 4客户端坐标签章;5客户端关键字签章;)
                'signParam' => $data['sign_param'], // 签章配置,JSON
                'sealImg' => $data['seal_img'], // 签章图片，base64格式
                'sealType' => "4",
                'signTemplate' => "0",
            ]
        ];

        try {
            $response = $this->httpRequest(
                config("ca.api_url") . '/signature-server/api/open/signature/userSignConfig',
                $option
            );

            return true;
        } catch (GuzzleException $e) {
            throw new BusinessException($e->getMessage());
        }
    }

    /**
     * 删除签章配置
     * @param string $user_id
     * @return mixed
     */
    public function deleteUserSignConfig(string $user_id): mixed
    {
        $option = [
            'form_params' => [
                'userId' => $user_id,//用户标识信息（为云证书entityId）
                'configKey' => $user_id, // 签章配置唯一标识，一张云证书配置一个
            ]
        ];

        try {
            $this->httpRequest(
                config("ca.api_url") . '/signature-server/api/open/signature/delSignConfig',
                $option
            );
            return true;
        } catch (GuzzleException $e) {
            throw new BusinessException($e->getMessage());
        }
    }

    /**
     * 获取用户签章图片
     * @param string $user_id
     * @return mixed
     */
    public function getFetchUserSeal(string $user_id): mixed
    {
        $option = [
            'form_params' => [
                'userId' => $user_id,//用户标识信息（为云证书entityId）
            ]
        ];

        try {
            $response = $this->httpRequest(
                config("ca.api_url") . '/signature-server/api/open/signature/fetchUserSeal',
                $option
            );
            if (empty($response)) {
                // 返回值为空
                throw new BusinessException(HttpEnumCode::getMessage(HttpEnumCode::SERVER_ERROR));
            }
            return $response;
        } catch (GuzzleException $e) {
            throw new BusinessException($e->getMessage());
        }
    }

    /**
     * PDF添加电子签章
     * @param string $user_id
     * @param array $data
     * @return mixed
     */
    public function addSignPdf(string $user_id, array $data)
    {
        $option = [
            'multipart' => [
                [
                    'name' => 'pdfFile',
                    'contents' => $data['pdf_file'],// 待签章PDF文件（字节流）
                ],
                [
                    'name' => 'userId',
                    'contents' => $user_id, // 用户标识信息
                ],
                [
                    'name' => 'configKey',
                    'contents' => $user_id, // 签章配置唯一标识
                ],
                [
                    'name' => 'signParams',
                    'contents' => $data['sign_param'],// 签章参数，JSON格式数据,如果不指定，那么以签章配置接口配置为准
                ],
                [
                    'name' => 'cloudCertPass',
                    'contents' => $user_id,// 云证书PIN码，云证书签章时使用
                ],
            ]
        ];

        try {
            $response = $this->httpRequest(
                config("ca.api_url") . '/signature-server/api/open/signature/signPdf',
                $option
            );

            if (empty($response)) {
                // 返回值为空
                throw new BusinessException(HttpEnumCode::getMessage(HttpEnumCode::SERVER_ERROR));
            }
            return $response;
        } catch (GuzzleException $e) {
            throw new BusinessException($e->getMessage());
        }
    }

    /**
     * 下载签章的pdf文件
     * @param string $user_id
     * @param string $file_id
     * @return mixed
     */
    public function getSignedFile(string $user_id, string $file_id): mixed
    {
        $arg = [
            'form_params' => [
                'userId' => $user_id,// 用户标识信息（为云证书entityId）
                'fileId' => $file_id,// 签章接口返回的文件标识
            ]
        ];

        try {
            $option = [
                "headers" => [
                    "app_id" => config("ca.app_id"),
                    "signature" => $this->getRequestSign($arg),
                ],
            ];

            $option = array_merge($arg, $option);

            $response = $this->client->post(config("ca.api_url") . '/signature-server/api/open/signature/fetchSignedFile', $option);

            if ($response->getStatusCode() != '200') {
                // 请求失败
                throw new BusinessException($response->getBody()->getContents());
            }

            // 将 Stream 对象转换为字符串
            return (string)$response->getBody()->getContents();
        } catch (GuzzleException $e) {
            throw new BusinessException($e->getMessage());
        }
    }

    /**
     * PDF签章文件验证
     * @param array $data
     * @return mixed
     */
    public function verifyPdf(array $data): mixed
    {
        $option = [
            'multipart' => [
                [
                    'name' => 'pdfFile',
                    'contents' => $data['pdf_file'],// 待签章PDF文件（字节流）
                ],
            ]
        ];

        try {
            $response = $this->httpRequest(
                config("ca.api_url") . '/signature-server/api/open/signature/verifyPdf',
                $option
            );

            if (empty($response)) {
                // 返回值为空
                throw new BusinessException(HttpEnumCode::getMessage(HttpEnumCode::SERVER_ERROR));
            }
            return $response;
        } catch (GuzzleException $e) {
            throw new BusinessException($e->getMessage());
        }
    }

    /**
     * 获取请求签名
     * @param array $data
     * @return string
     */
    protected function getRequestSign(array $data): string
    {
        $sign_data = array();
        if (isset($data['form_params'])) {
            $sign_data = $data['form_params'];
        }

        if (isset($data['multipart'])) {
            foreach ($data['multipart'] as $item) {
                // pdf进行签章时，此参数为文件流，不参与签名
                if ($item['name'] == "pdfFile") {
                    continue;
                }

                $sign_data[$item['name']] = $item['contents'];
            }
        }

        if (!empty($sign_data)){
            ksort($sign_data);
            $data = implode('&', $sign_data);
        }else{
            $data = "";
        }

        return hash_hmac("sha1", $data, config("ca.secret"));
    }

    /**
     * 封装公共请求
     * @param string $path
     * @param array $arg
     * @return mixed
     * @throws GuzzleException
     */
    protected function httpRequest(string $path, array $arg = []): mixed
    {
        $option = [
            "headers" => [
                "app_id" => config("ca.app_id"),
                "signature" => $this->getRequestSign($arg),
            ],
        ];

        $arg = array_merge($arg, $option);

        $response = $this->client->post($path, $arg);

        if ($response->getStatusCode() != '200') {
            // 请求失败
            throw new BusinessException($response->getBody()->getContents());
        }
        $body = json_decode($response->getBody(), true);
        dump($body);
        if (empty($body)) {
            // 返回值为空
            throw new BusinessException(HttpEnumCode::getMessage(HttpEnumCode::SERVER_ERROR));
        }

        if ($body['result_code'] != 0) {
            // 请求失败
            if (!empty($body['result_msg'])) {
                throw new BusinessException($body['result_msg']);
            }
            throw new BusinessException(HttpEnumCode::getMessage(HttpEnumCode::SERVER_ERROR));
        }

        return $body['body'];
    }
}