<?php
namespace lib\Storage;
use \lib\IStorage;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7;

class Rainyun implements IStorage {
	private $config;
	private $bucket;
	private $endpoint;
	private $accessKey;
	private $secretKey;
	private $client;
	private $errmsg;
	private $filepath = 'file/';
	
	public function __construct($config) {
		$this->bucket = $config['bucket'];
		$this->endpoint = $config['endpoint'];
		$this->accessKey = $config['accessKey'];
		$this->secretKey = $config['secretKey'];
		$this->config = $config;
		
		// 确保endpoint格式正确
		if (!preg_match('/^https?:\/\//', $this->endpoint)) {
			$this->endpoint = 'https://' . $this->endpoint;
		}
		
		$this->client = new Client([
			'timeout' => 60,
			'verify' => false
		]);
	}

	public function getClient(){
		return $this->client;
	}

	public function errmsg(){
		return $this->errmsg;
	}

	/**
	 * 生成S3签名
	 */
	private function generateSignature($method, $uri, $headers = [], $payload = '') {
		$date = gmdate('D, d M Y H:i:s \G\M\T');
		$headers['Date'] = $date;
		
		// 构建签名字符串
		$stringToSign = $method . "\n";
		$stringToSign .= "\n"; // Content-MD5
		$stringToSign .= (isset($headers['Content-Type']) ? $headers['Content-Type'] : '') . "\n";
		$stringToSign .= $date . "\n";
		
		// 添加CanonicalizedAmzHeaders
		$canonicalizedHeaders = [];
		foreach ($headers as $key => $value) {
			$lowerKey = strtolower($key);
			if (strpos($lowerKey, 'x-amz-') === 0) {
				$canonicalizedHeaders[$lowerKey] = $lowerKey . ':' . trim($value);
			}
		}
		ksort($canonicalizedHeaders);
		$stringToSign .= implode("\n", $canonicalizedHeaders);
		if (!empty($canonicalizedHeaders)) {
			$stringToSign .= "\n";
		}
		
		// 添加CanonicalizedResource
		$stringToSign .= '/' . $this->bucket . '/' . $uri;
		
		// 生成签名
		$signature = base64_encode(hash_hmac('sha1', $stringToSign, $this->secretKey, true));
		
		return [
			'date' => $date,
			'signature' => $signature,
			'auth' => 'AWS ' . $this->accessKey . ':' . $signature
		];
	}

	/**
	 * 发送S3请求
	 */
	private function s3Request($method, $uri, $headers = [], $body = null) {
		$signInfo = $this->generateSignature($method, $uri, $headers);
		
		$url = $this->endpoint . '/' . $this->bucket . '/' . $uri;
		
		$requestHeaders = [
			'Date' => $signInfo['date'],
			'Authorization' => $signInfo['auth']
		];
		
		// 合并自定义headers
		foreach ($headers as $key => $value) {
			$requestHeaders[$key] = $value;
		}
		
		$options = [
			'headers' => $requestHeaders
		];
		
		if ($body !== null) {
			$options['body'] = $body;
		}
		
		try {
			$response = $this->client->request($method, $url, $options);
			return $response;
		} catch (\Exception $e) {
			$this->errmsg = $e->getMessage();
			return false;
		}
	}

	public function exists($name) {
		$uri = $this->filepath . $name;
		$response = $this->s3Request('HEAD', $uri);
		return $response !== false && $response->getStatusCode() === 200;
	}

	public function get($name) {
		$uri = $this->filepath . $name;
		$response = $this->s3Request('GET', $uri);
		if ($response === false) {
			return false;
		}
		return (string)$response->getBody();
	}

	public function downfile($name, $range = false) {
		$uri = $this->filepath . $name;
		$headers = [];
		
		if ($range) {
			$headers['Range'] = 'bytes=' . $range[0] . '-' . $range[1];
		}
		
		$response = $this->s3Request('GET', $uri, $headers);
		if ($response === false) {
			return false;
		}
		
		$body = $response->getBody();
		while (!$body->eof()) {
			echo $body->read(102400);
			flush();
		}
		
		return true;
	}

	public function upload($name, $tmpfile, $content_type = null) {
		$uri = $this->filepath . $name;
		$headers = [];
		
		if ($content_type) {
			$headers['Content-Type'] = $content_type;
		}
		
		$body = fopen($tmpfile, 'rb');
		$response = $this->s3Request('PUT', $uri, $headers, $body);
		
		if ($response === false) {
			return false;
		}
		
		return $response->getStatusCode() === 200;
	}

	public function savefile($name, $tmpfile, $content_type = null) {
		return $this->upload($name, $tmpfile, $content_type);
	}

	public function getinfo($name) {
		$uri = $this->filepath . $name;
		$response = $this->s3Request('HEAD', $uri);
		
		if ($response === false) {
			return false;
		}
		
		$result = [
			'length' => $response->getHeaderLine('Content-Length'),
			'content_type' => $response->getHeaderLine('Content-Type')
		];
		
		return $result;
	}

	public function delete($name) {
		$uri = $this->filepath . $name;
		$response = $this->s3Request('DELETE', $uri);
		
		if ($response === false) {
			return false;
		}
		
		return $response->getStatusCode() === 204 || $response->getStatusCode() === 200;
	}

	public function getUploadParam($name, $filename, $max_file_size = 0){
		global $conf;
		
		$uri = $this->filepath . $name;
		$url = $this->endpoint . '/' . $this->bucket . '/' . $uri;
		
		// 生成预签名URL (简化版，实际可能需要更复杂的实现)
		$expires = time() + 3600;
		$signInfo = $this->generateSignature('PUT', $uri, ['Content-Type' => 'application/octet-stream']);
		
		$uploadUrl = $url . '?AWSAccessKeyId=' . $this->accessKey . 
					'&Expires=' . $expires . 
					'&Signature=' . urlencode($signInfo['signature']);
		
		$post = [
			'key' => $uri,
			'policy' => base64_encode(json_encode([
				'expiration' => date('Y-m-d\TH:i:s.000\Z', $expires),
				'conditions' => [
					['bucket' => $this->bucket],
					['eq', '$key', $uri]
				]
			])),
			'Signature' => $signInfo['signature'],
			'AWSAccessKeyId' => $this->accessKey,
			'success_action_status' => '200'
		];
		
		return ['url' => $url, 'post' => $post];
	}

	public function getDownUrl($name, $filename = null, $content_type = null){
		global $conf;
		
		$uri = $this->filepath . $name;
		$url = $this->endpoint . '/' . $this->bucket . '/' . $uri;
		
		// 添加签名参数
		$expires = time() + 315360000; // 10年
		$signInfo = $this->generateSignature('GET', $uri);
		
		$url .= '?AWSAccessKeyId=' . $this->accessKey . 
				'&Expires=' . $expires . 
				'&Signature=' . urlencode($signInfo['signature']);
		
		// 如果指定了下载域名
		if (!empty($conf['downfile_domain'])) {
			$url = ($conf['downfile_protocol'] == 1 ? 'https://' : 'http://') . 
				   $conf['downfile_domain'] . '/' . $uri;
		}
		
		// 添加响应头参数
		if ($filename) {
			if ($content_type) {
				$url .= '&response-content-type=' . urlencode($content_type);
				$url .= '&response-content-disposition=' . urlencode('inline; filename=' . $filename);
			} else {
				$url .= '&response-content-type=' . urlencode('application/force-download');
				$url .= '&response-content-disposition=' . urlencode('attachment; filename=' . $filename);
			}
		}
		
		return $url;
	}
}