<?php

namespace Kylin\Sms\Gateways;

use Kylin\Sms\Exceptions\GatewayException;

/**
 * 火山引擎短信网关
 * 
 * 支持火山引擎短信服务的发送功能
 * 火山引擎是字节跳动旗下的云服务平台，提供稳定可靠的短信发送能力
 * 
 * 文档：https://www.volcengine.com/docs/639/63968
 * 
 * @package Kylin\Sms\Gateways
 */
class VolcengineGateway extends BaseGateway
{
    /**
     * 网关名称标识
     */
    protected static string $name = 'volcengine';

    /**
     * API 请求地址
     */
    protected const API_URL = 'https://sms.volcengineapi.com';

    /**
     * 火山引擎 Access Key
     * 
     * @var string
     */
    protected string $accessKey;

    /**
     * 火山引擎 Secret Key
     * 
     * @var string
     */
    protected string $secretKey;

    /**
     * 短信签名
     * 
     * @var string
     */
    protected string $signName;

    /**
     * 短信账号
     * 
     * @var string
     */
    protected string $smsAccount;

    /**
     * 地域
     * 
     * @var string
     */
    protected string $region;

    /**
     * 构造函数
     * 
     * 初始化火山引擎短信网关配置
     * 
     * @param array $config 网关配置数组
     */
    public function __construct(array $config = [])
    {
        parent::__construct($config);
        $this->accessKey = $config['access_key'] ?? '';
        $this->secretKey = $config['secret_key'] ?? '';
        $this->signName = $config['sign_name'] ?? '';
        $this->smsAccount = $config['sms_account'] ?? '';
        $this->region = $config['region'] ?? 'cn-north-1';
    }

    /**
     * 发送短信
     * 
     * 发送短信到指定手机号
     * 
     * @param string $to 接收手机号
     * @param string $content 短信内容（火山引擎使用模板，此参数可忽略）
     * @param array $data 附加数据，包含 template_id 和 template_params
     * @return array 发送结果
     */
    public function send(string $to, string $content, array $data = []): array
    {
        $params = [
            'SmsAccount' => $this->smsAccount,
            'Sign' => $data['sign_name'] ?? $this->signName,
            'TemplateID' => $data['template_id'] ?? '',
            'PhoneNumbers' => $this->formatPhone($to),
            'TemplateParam' => json_encode($data['template_params'] ?? []),
        ];

        $headers = $this->buildHeaders('SendSms', $params);

        try {
            $response = $this->request('POST', self::API_URL, [
                'headers' => $headers,
                'json' => $params,
            ]);
            return $this->parseResponse($response);
        } catch (GatewayException $e) {
            return $this->buildErrorResponse($e->getMessage(), $e->getCode(), $e->getContext());
        }
    }

    /**
     * 发送模板短信
     * 
     * 使用预定义模板发送短信
     * 
     * @param string $to 接收手机号
     * @param string $templateId 模板 ID
     * @param array $params 模板参数
     * @return array 发送结果
     */
    public function sendTemplate(string $to, string $templateId, array $params = []): array
    {
        return $this->send($to, '', [
            'template_id' => $templateId,
            'template_params' => $params,
        ]);
    }

    /**
     * 批量发送短信
     * 
     * 向多个手机号发送相同内容的短信
     * 
     * @param array $recipients 接收手机号数组
     * @param string $content 短信内容
     * @param array $data 附加数据
     * @return array 发送结果
     */
    public function sendBatch(array $recipients, string $content, array $data = []): array
    {
        $params = [
            'SmsAccount' => $this->smsAccount,
            'Sign' => $data['sign_name'] ?? $this->signName,
            'TemplateID' => $data['template_id'] ?? '',
            'PhoneNumbers' => implode(',', array_map([$this, 'formatPhone'], $recipients)),
            'TemplateParam' => json_encode($data['template_params'] ?? []),
        ];

        $headers = $this->buildHeaders('SendSms', $params);

        try {
            $response = $this->request('POST', self::API_URL, [
                'headers' => $headers,
                'json' => $params,
            ]);
            return $this->parseResponse($response);
        } catch (GatewayException $e) {
            return $this->buildErrorResponse($e->getMessage(), $e->getCode(), $e->getContext());
        }
    }

    /**
     * 构建请求头
     * 
     * 生成火山引擎 API 所需的认证头信息
     * 
     * @param string $action API 操作名称
     * @param array $params 请求参数
     * @return array 请求头数组
     */
    protected function buildHeaders(string $action, array $params): array
    {
        $timestamp = gmdate('Ymd\THis\Z');
        $version = '2020-01-01';
        $service = 'sms';
        $contentType = 'application/json';

        $canonicalHeaders = "content-type:{$contentType}\nhost:sms.volcengineapi.com\n";
        $signedHeaders = 'content-type;host';
        $hashedPayload = hash('sha256', json_encode($params));
        $canonicalRequest = "POST\n/\n\n{$canonicalHeaders}\n{$signedHeaders}\n{$hashedPayload}";

        $credentialScope = date('Ymd') . "/{$this->region}/{$service}/request";
        $hashedCanonicalRequest = hash('sha256', $canonicalRequest);
        $stringToSign = "HMAC-SHA256\n{$timestamp}\n{$credentialScope}\n{$hashedCanonicalRequest}";

        $kDate = hash_hmac('sha256', date('Ymd'), $this->secretKey, true);
        $kRegion = hash_hmac('sha256', $this->region, $kDate, true);
        $kService = hash_hmac('sha256', $service, $kRegion, true);
        $kSigning = hash_hmac('sha256', 'request', $kService, true);
        $signature = hash_hmac('sha256', $stringToSign, $kSigning);

        $authorization = "HMAC-SHA256 Credential={$this->accessKey}/{$credentialScope}, SignedHeaders={$signedHeaders}, Signature={$signature}";

        return [
            'Authorization' => $authorization,
            'Content-Type' => $contentType,
            'Host' => 'sms.volcengineapi.com',
            'X-Date' => $timestamp,
            'X-Content-Sha256' => $hashedPayload,
            'X-Action' => $action,
            'X-Version' => $version,
        ];
    }

    /**
     * 解析响应结果
     * 
     * 将火山引擎 API 响应转换为标准化的结果格式
     * 
     * @param array $response API 响应
     * @return array 标准化的响应结果
     */
    protected function parseResponse(array $response): array
    {
        if (isset($response['ResponseMetadata']['Error'])) {
            return $this->buildErrorResponse(
                $response['ResponseMetadata']['Error']['Message'] ?? '发送失败',
                $response['ResponseMetadata']['Error']['Code'] ?? 500,
                $response
            );
        }

        if (isset($response['Result'])) {
            return $this->buildSuccessResponse([
                'message_id' => $response['Result']['MessageID'] ?? '',
            ]);
        }

        return $this->buildErrorResponse('未知响应格式', 500, $response);
    }
}
