<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
namespace app\service\domain\storage\gateway;

use app\service\domain\storage\StorageConfigService;
use think\App;
use think\facade\Log;


/**
 * Tencent Cos Gateway
 * @package app\service\domain\storage\gateway
 */
class TencentCosGateway extends BaseStorageGateway
{
    private App $app;
    private StorageConfigService $config;

    /**
     * Tencent Cos Gateway constructor�造函数
     * @param App $app 应用实例
     * @param StorageConfigService $config 存储配置服务
     */
    public function __construct(App $app, StorageConfigService $config)
    {
        $this->app = $app;
        $this->config = $config;
    }

    /**
     * 上传文件到腾讯云 COS 存储
     * @param string $localPath 本地文件路径
     * @param string $remotePath 远程文件路径
     * @param array $options 上传选项
     * @return array 上传结果
     */
    public function upload(string $localPath, string $remotePath, array $options = []): array
    {
        $object = $this->normalizePath($remotePath);
        $bucket = $this->config->tencentBucket();
        $region = $this->config->tencentRegion();
        $host = $bucket . '.cos.' . $region . '.myqcloud.com';
        $content = @file_get_contents($localPath);

        if ($content === false) {
            throw new \RuntimeException('');
        }

        $contentLength = strlen($content);
        $now = time();
        $keyTime = $now . ';' . ($now + 3600);
        $uriPathname = '/' . ltrim($object, '/');


        $headerList = 'content-length;host';
        $httpHeaders = "content-length={$contentLength}&host={$host}";
        $httpString = "put\n{$uriPathname}\n\n{$httpHeaders}\n";
        $stringToSign = "sha1\n{$keyTime}\n" . sha1($httpString) . "\n";

        $signKey = hash_hmac('sha1', $keyTime, $this->config->tencentSecretKey());
        $signature = hash_hmac('sha1', $stringToSign, $signKey);

        $qHeaderList = $headerList;
        $qSignAlgorithm = 'sha1';
        $authorization = "q-sign-algorithm={$qSignAlgorithm}&q-ak={$this->config->tencentSecretId()}&q-sign-time={$keyTime}&q-key-time={$keyTime}&q-header-list={$qHeaderList}&q-url-param-list=&q-signature={$signature}";

        $client = new \GuzzleHttp\Client(['timeout' => 30]);
        $response = $client->put("https://{$host}{$uriPathname}", [
            'headers' => [
                'Authorization' => $authorization,
                'Host' => $host,
                'Content-Length' => (string)$contentLength,
            ],
            'body' => $content,
        ]);

        if ($response->getStatusCode() !== 200) {
            Log::error('tencent_cos upload failed: ' . $response->getStatusCode());
            throw new \RuntimeException('' . $response->getStatusCode());
        }

        return [
            'url' => "https://{$host}{$uriPathname}",
            'path' => $object,
        ];
    }

    /**
     * 删除腾讯云 COS 存储中的文件
     * @param string $remotePath 远程文件路径
     * @return bool 是否删除成功
     */
    public function delete(string $remotePath): bool
    {
        $object = $this->normalizePath($remotePath);
        $bucket = $this->config->tencentBucket();
        $region = $this->config->tencentRegion();
        $host = $bucket . '.cos.' . $region . '.myqcloud.com';
        $uriPathname = '/' . ltrim($object, '/');
        $now = time();
        $keyTime = $now . ';' . ($now + 3600);

        $httpString = "delete\n{$uriPathname}\n\nhost={$host}\n";
        $stringToSign = "sha1\n{$keyTime}\n" . sha1($httpString) . "\n";
        $signKey = hash_hmac('sha1', $keyTime, $this->config->tencentSecretKey());
        $signature = hash_hmac('sha1', $stringToSign, $signKey);
        $authorization = "q-sign-algorithm=sha1&q-ak={$this->config->tencentSecretId()}&q-sign-time={$keyTime}&q-key-time={$keyTime}&q-header-list=host&q-url-param-list=&q-signature={$signature}";

        $client = new \GuzzleHttp\Client(['timeout' => 10]);
        $response = $client->delete("https://{$host}{$uriPathname}", [
            'headers' => [
                'Authorization' => $authorization,
                'Host' => $host,
            ],
        ]);

        return in_array($response->getStatusCode(), [200, 204], true);
    }

    /**
     * 获取腾讯云 COS 存储中的文件 URL
     * @param string $remotePath 远程文件路径
     * @param int $expireSeconds 过期时间（秒）
     * @return string 文件 URL
     */
    public function url(string $remotePath, int $expireSeconds = 0): string
    {
        $object = $this->normalizePath($remotePath);
        $bucket = $this->config->tencentBucket();
        $region = $this->config->tencentRegion();

        if ($expireSeconds > 0) {
            $now = time();
            $keyTime = $now . ';' . ($now + $expireSeconds);
            $uriPathname = '/' . ltrim($object, '/');
            $httpString = "get\n{$uriPathname}\n\nhost={$bucket}.cos.{$region}.myqcloud.com\n";
            $stringToSign = "sha1\n{$keyTime}\n" . sha1($httpString) . "\n";
            $signKey = hash_hmac('sha1', $keyTime, $this->config->tencentSecretKey());
            $signature = hash_hmac('sha1', $stringToSign, $signKey);
            $authorization = urlencode("q-sign-algorithm=sha1&q-ak={$this->config->tencentSecretId()}&q-sign-time={$keyTime}&q-key-time={$keyTime}&q-header-list=host&q-url-param-list=&q-signature={$signature}");
            return "https://{$bucket}.cos.{$region}.myqcloud.com{$uriPathname}?sign={$authorization}";
        }

        return "https://{$bucket}.cos.{$region}.myqcloud.com/" . ltrim($object, '/');
    }

    /**
     * 获取存储提供程序名称
     * @return string 存储提供程序名称
     */
    public function provider(): string
    {
        return 'tencent_cos';
    }

    /**
     * 获取存储名称
     * @return string 存储名称
     */
    public function name(): string
    {
        return '';
    }

    /**
     * 检查存储配置是否已配置
     * @return bool 是否已配置
     */
    public function isConfigured(): bool
    {
        return $this->config->tencentSecretId() !== ''
            && $this->config->tencentSecretKey() !== ''
            && $this->config->tencentRegion() !== ''
            && $this->config->tencentBucket() !== '';
    }
}