<?php

namespace Kylin\Storage\Adapters;

use Kylin\Storage\Contracts\StorageAdapterInterface;

class S3Adapter implements StorageAdapterInterface
{
    private object $client;
    private string $bucket;
    private string $domain;
    private bool $pathStyle;

    public function __construct(array $config)
    {
        $this->bucket = $config['bucket'];
        $this->domain = rtrim($config['domain'] ?? '', '/');
        $this->pathStyle = $config['path_style'] ?? true;

        // 使用 AWS SDK S3Client（需 aws/aws-sdk-php）
        // 或通过 Guzzle 直接实现 S3 签名请求
        $this->client = new \Aws\S3\S3Client([
            'version' => 'latest',
            'region' => $config['region'] ?? 'us-east-1',
            'endpoint' => $config['endpoint'],
            'use_path_style_endpoint' => $this->pathStyle,
            'credentials' => [
                'key' => $config['access_key'],
                'secret' => $config['secret_key'],
            ],
            'http' => [
                'verify' => $config['verify_ssl'] ?? true,
            ],
        ]);
    }

    public function upload(string $localPath, string $remotePath, array $options = []): string
    {
        $this->client->putObject(array_merge([
            'Bucket' => $this->bucket,
            'Key' => $remotePath,
            'SourceFile' => $localPath,
        ], $options));

        return $remotePath;
    }

    public function download(string $remotePath, ?string $localPath = null): string
    {
        $localPath = $localPath ?? tempnam(sys_get_temp_dir(), 'kylin_s3_');

        $this->client->getObject([
            'Bucket' => $this->bucket,
            'Key' => $remotePath,
            'SaveAs' => $localPath,
        ]);

        return $localPath;
    }

    public function delete(string $remotePath): bool
    {
        $this->client->deleteObject([
            'Bucket' => $this->bucket,
            'Key' => $remotePath,
        ]);

        return true;
    }

    public function getUrl(string $remotePath): string
    {
        if ($this->domain) {
            return $this->domain . '/' . ltrim($remotePath, '/');
        }

        return $this->getSignedUrl($remotePath, 3600);
    }

    public function getSignedUrl(string $remotePath, int $expires = 3600): string
    {
        $command = $this->client->getCommand('GetObject', [
            'Bucket' => $this->bucket,
            'Key' => $remotePath,
        ]);

        $request = $this->client->createPresignedRequest($command, "+{$expires} seconds");

        return (string) $request->getUri();
    }

    public function exists(string $remotePath): bool
    {
        try {
            $this->client->headObject([
                'Bucket' => $this->bucket,
                'Key' => $remotePath,
            ]);
            return true;
        } catch (\Throwable) {
            return false;
        }
    }

    public function getSize(string $remotePath): int
    {
        $result = $this->client->headObject([
            'Bucket' => $this->bucket,
            'Key' => $remotePath,
        ]);

        return (int) $result['ContentLength'];
    }

    public function getMimeType(string $remotePath): string
    {
        $result = $this->client->headObject([
            'Bucket' => $this->bucket,
            'Key' => $remotePath,
        ]);

        return $result['ContentType'] ?? 'application/octet-stream';
    }
}
