<?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;


/**
 * Qiniu Kodo Gateway
 * @package app\service\domain\storage\gateway
 */
class QiniuKodoGateway extends BaseStorageGateway
{
    private App $app;
    private StorageConfigService $config;

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

    /**
     * 上传文件到七牛 Kodo 存储
     * @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->qiniuBucket();
        $domain = $this->config->qiniuDomain();
        $accessKey = $this->config->qiniuAccessKey();


        $putPolicy = base64_encode(json_encode([
            'scope' => $bucket . ':' . $object,
            'deadline' => time() + 3600,
        ]));
        $sign = $this->qiniuSign($putPolicy, $this->config->qiniuSecretKey());
        $uploadToken = $accessKey . ':' . $sign . ':' . $putPolicy;

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


        $uploadHost = 'https://upload.qiniup.com';
        if (str_contains($domain, 'z0')) {
            $uploadHost = 'https://upload.qiniup.com';
        } elseif (str_contains($domain, 'z1')) {
            $uploadHost = 'https://upload-z1.qiniup.com';
        } elseif (str_contains($domain, 'z2')) {
            $uploadHost = 'https://upload-z2.qiniup.com';
        }

        $client = new \GuzzleHttp\Client(['timeout' => 30]);
        $response = $client->post($uploadHost, [
            'multipart' => [
                ['name' => 'token', 'contents' => $uploadToken],
                ['name' => 'key', 'contents' => $object],
                ['name' => 'file', 'contents' => $content, 'filename' => basename($remotePath)],
            ],
        ]);

        $body = json_decode((string)$response->getBody(), true);
        if ((int)($body['error'] ?? 1) !== 0 && $response->getStatusCode() !== 200) {
            Log::error('qiniu_kodo upload failed: ' . ($body['error'] ?? 'unknown'));
            throw new \RuntimeException('');
        }

        $scheme = parse_url($domain, PHP_URL_SCHEME) ?: 'https';
        $host = parse_url($domain, PHP_URL_HOST) ?: $domain;
        $baseUrl = rtrim($scheme . '://' . $host, '/');

        return [
            'url' => $baseUrl . '/' . ltrim($object, '/'),
            'path' => $object,
        ];
    }

    /**
     * 删除七牛 Kodo 存储中的文件
     * @param string $remotePath 远程文件路径
     * @return bool 是否删除成功
     */
    public function delete(string $remotePath): bool
    {
        $object = $this->normalizePath($remotePath);
        $bucket = $this->config->qiniuBucket();
        $accessKey = $this->config->qiniuAccessKey();
        $secretKey = $this->config->qiniuSecretKey();

        $path = '/delete/' . base64_encode($bucket . ':' . $object);
        $host = 'rs.qiniu.com';
        $contentType = 'application/x-www-form-urlencoded';
        $body = '';
        $sign = $this->qiniuManageSign($path, $body, $contentType, $accessKey, $secretKey);

        $client = new \GuzzleHttp\Client(['timeout' => 10]);
        $response = $client->post("https://{$host}{$path}", [
            'headers' => [
                'Authorization' => 'QBox ' . $sign,
                'Content-Type' => $contentType,
            ],
            'body' => $body,
        ]);

        $result = json_decode((string)$response->getBody(), true);
        return isset($result['error']) && (int)$result['error'] === 0;
    }

    /**
     * 获取七牛 Kodo 存储中的文件 URL
     * @param string $remotePath 远程文件路径
     * @param int $expireSeconds 过期时间（秒）
     * @return string 文件 URL
     */
    public function url(string $remotePath, int $expireSeconds = 0): string
    {
        $object = $this->normalizePath($remotePath);
        $domain = $this->config->qiniuDomain();
        $scheme = parse_url($domain, PHP_URL_SCHEME) ?: 'https';
        $host = parse_url($domain, PHP_URL_HOST) ?: $domain;
        $baseUrl = rtrim($scheme . '://' . $host, '/');

        if ($expireSeconds > 0) {
            $deadline = time() + $expireSeconds;
            $url = $baseUrl . '/' . ltrim($object, '/') . '?e=' . $deadline;
            $sign = $this->qiniuSign($url, $this->config->qiniuSecretKey());
            return $url . '&token=' . $this->config->qiniuAccessKey() . ':' . $sign;
        }

        return $baseUrl . '/' . ltrim($object, '/');
    }

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

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

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


    /**
     * 生成七牛上传凭证签名
     * 使用HMAC-SHA1对数据进行签名后做Base64 URL安全编码
     * @param string $data 待签名数据
     * @param string $secretKey 密钥
     * @return string 签名结果
     */
    private function qiniuSign(string $data, string $secretKey): string
    {
        $sign = hash_hmac('sha1', $data, $secretKey, true);
        return str_replace(['+', '/'], ['-', '_'], base64_encode($sign));
    }


    /**
     * 生成七牛管理API签名（QBox格式）
     * @param string $path 请求路径
     * @param string $body 请求体
     * @param string $contentType 内容类型
     * @param string $accessKey 访问密钥
     * @param string $secretKey 密钥
     * @return string 签名字符串
     */
    private function qiniuManageSign(string $path, string $body, string $contentType, string $accessKey, string $secretKey): string
    {
        $data = $path . "\n";
        $sign = hash_hmac('sha1', $data, $secretKey, true);
        return $accessKey . ':' . str_replace(['+', '/'], ['-', '_'], base64_encode($sign));
    }
}