<?php

namespace App\Filesystem;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use League\Flysystem\Adapter\AbstractAdapter;
use League\Flysystem\Config;

class HttpGoAdapter extends AbstractAdapter
{
    protected Client $client;
    protected string $baseUri;

    public function __construct(string $baseUri)
    {
        $this->baseUri = rtrim($baseUri, '/');
        $this->client = new Client([
            'base_uri' => $this->baseUri . '/',
            'timeout'  => 30,
            'http_errors' => false,
        ]);
    }

    /**
     * 写入文件（base64 方式）
     */
    public function write($path, $contents, Config $config): array|false
    {
        $fullPath = $this->applyPathPrefix($path);
        $dir = dirname($fullPath);
        $filename = basename($fullPath);

        try {
            $response = $this->client->post('api/upload/base64', [
                'json' => [
                    'file'     => base64_encode($contents),
                    'path'     => $dir,
                    'filename' => $filename,
                ],
            ]);

            if ($response->getStatusCode() !== 200) {
                return false;
            }

            $body = json_decode($response->getBody(), true);
            if (($body['code'] ?? 0) !== 200) {
                return false;
            }

            return $this->normalizeMetadata($fullPath, $config);
        } catch (GuzzleException $e) {
            return false;
        }
    }

    /**
     * 写入文件流（multipart 方式）
     */
    public function writeStream($path, $resource, Config $config): array|false
    {
        $fullPath = $this->applyPathPrefix($path);
        $dir = dirname($fullPath);
        $filename = basename($fullPath);

        // 将流转换为临时文件
        $tmpFile = tmpfile();
        stream_copy_to_stream($resource, $tmpFile);
        $meta = stream_get_meta_data($tmpFile);

        try {
            $response = $this->client->post('api/upload/file', [
                'multipart' => [
                    [
                        'name'     => 'file',
                        'contents' => fopen($meta['uri'], 'r'),
                        'filename' => $filename,
                    ],
                    [
                        'name'     => 'path',
                        'contents' => $dir,
                    ],
                ],
            ]);

            fclose($tmpFile);

            if ($response->getStatusCode() !== 200) {
                return false;
            }

            $body = json_decode($response->getBody(), true);
            if (($body['code'] ?? 0) !== 200) {
                return false;
            }

            return $this->normalizeMetadata($fullPath, $config);
        } catch (GuzzleException $e) {
            fclose($tmpFile);
            return false;
        }
    }

    /**
     * 更新文件（委托给 write）
     */
    public function update($path, $contents, Config $config): array|false
    {
        return $this->write($path, $contents, $config);
    }

    /**
     * 更新文件流（委托给 writeStream）
     */
    public function updateStream($path, $resource, Config $config): array|false
    {
        return $this->writeStream($path, $resource, $config);
    }

    /**
     * 读取文件内容
     */
    public function read($path): array|false
    {
        $fullPath = $this->applyPathPrefix($path);

        try {
            $response = $this->client->get('files/' . ltrim($fullPath, '/'));

            if ($response->getStatusCode() !== 200) {
                return false;
            }

            return ['contents' => $response->getBody()->getContents()];
        } catch (GuzzleException $e) {
            return false;
        }
    }

    /**
     * 读取文件流
     */
    public function readStream($path): array|false
    {
        $fullPath = $this->applyPathPrefix($path);

        try {
            $response = $this->client->get('files/' . ltrim($fullPath, '/'), [
                'stream' => true,
            ]);

            if ($response->getStatusCode() !== 200) {
                return false;
            }

            // 返回一个临时流
            $tmpFile = tmpfile();
            $stream = $response->getBody()->detach();
            if ($stream === null) {
                fclose($tmpFile);
                return false;
            }
            stream_copy_to_stream($stream, $tmpFile);
            fclose($stream);
            rewind($tmpFile);

            return ['stream' => $tmpFile];
        } catch (GuzzleException $e) {
            return false;
        }
    }

    /**
     * 检查文件是否存在
     */
    public function has($path): bool
    {
        $fullPath = $this->applyPathPrefix($path);

        try {
            $response = $this->client->head('files/' . ltrim($fullPath, '/'));
            return $response->getStatusCode() === 200;
        } catch (GuzzleException $e) {
            return false;
        }
    }

    /**
     * 删除文件
     */
    public function delete($path): bool
    {
        $fullPath = $this->applyPathPrefix($path);

        try {
            $response = $this->client->delete('files/' . ltrim($fullPath, '/'));
            return $response->getStatusCode() === 200;
        } catch (GuzzleException $e) {
            return false;
        }
    }

    /**
     * 删除目录
     */
    public function deleteDir($dirname): bool
    {
        $fullPath = $this->applyPathPrefix($dirname);

        try {
            $response = $this->client->delete('files/' . ltrim($fullPath, '/'));
            return $response->getStatusCode() === 200;
        } catch (GuzzleException $e) {
            return false;
        }
    }

    /**
     * 创建目录（Go 服务隐式创建，直接返回成功）
     */
    public function createDir($dirname, Config $config): array|false
    {
        return ['path' => $dirname, 'type' => 'dir'];
    }

    /**
     * 设置可见性（始终 public）
     */
    public function setVisibility($path, $visibility): array|false
    {
        return ['visibility' => $visibility, 'path' => $path];
    }

    /**
     * 获取可见性
     */
    public function getVisibility($path): array|false
    {
        return ['visibility' => 'public', 'path' => $path];
    }

    /**
     * 获取 MIME 类型
     */
    public function getMimetype($path): array|false
    {
        $fullPath = $this->applyPathPrefix($path);

        try {
            $response = $this->client->head('files/' . ltrim($fullPath, '/'));

            if ($response->getStatusCode() !== 200) {
                return false;
            }

            $contentType = $response->getHeader('Content-Type')[0] ?? 'application/octet-stream';
            return ['mimetype' => $contentType];
        } catch (GuzzleException $e) {
            return false;
        }
    }

    /**
     * 获取文件大小
     */
    public function getSize($path): array|false
    {
        $fullPath = $this->applyPathPrefix($path);

        try {
            $response = $this->client->head('files/' . ltrim($fullPath, '/'));

            if ($response->getStatusCode() !== 200) {
                return false;
            }

            $size = (int)($response->getHeader('Content-Length')[0] ?? 0);
            return ['size' => $size];
        } catch (GuzzleException $e) {
            return false;
        }
    }

    /**
     * 获取文件修改时间
     */
    public function getTimestamp($path): array|false
    {
        $fullPath = $this->applyPathPrefix($path);

        try {
            $response = $this->client->head('files/' . ltrim($fullPath, '/'));

            if ($response->getStatusCode() !== 200) {
                return false;
            }

            $lastModified = $response->getHeader('Last-Modified')[0] ?? '';
            $timestamp = $lastModified ? strtotime($lastModified) : time();
            return ['timestamp' => $timestamp];
        } catch (GuzzleException $e) {
            return false;
        }
    }

    /**
     * 获取文件元信息
     */
    public function getMetadata($path): array|false
    {
        $fullPath = $this->applyPathPrefix($path);

        try {
            $response = $this->client->head('files/' . ltrim($fullPath, '/'));

            if ($response->getStatusCode() !== 200) {
                return false;
            }

            $contentType = $response->getHeader('Content-Type')[0] ?? 'application/octet-stream';
            $size = (int)($response->getHeader('Content-Length')[0] ?? 0);
            $lastModified = $response->getHeader('Last-Modified')[0] ?? '';
            $timestamp = $lastModified ? strtotime($lastModified) : time();

            return [
                'type'      => 'file',
                'path'      => $fullPath,
                'timestamp' => $timestamp,
                'size'      => $size,
                'mimetype'  => $contentType,
            ];
        } catch (GuzzleException $e) {
            return false;
        }
    }

    /**
     * 列出目录内容（简化实现，返回空数组）
     */
    public function listContents($directory = '', $recursive = false): array
    {
        return [];
    }

    /**
     * 重命名文件
     */
    public function rename($path, $newpath): bool
    {
        $contents = $this->read($path);
        if ($contents === false) {
            return false;
        }

        if ($this->write($newpath, $contents['contents'], new Config()) === false) {
            return false;
        }

        return $this->delete($path);
    }

    /**
     * 复制文件
     */
    public function copy($path, $newpath): bool
    {
        $contents = $this->read($path);
        if ($contents === false) {
            return false;
        }

        return $this->write($newpath, $contents['contents'], new Config()) !== false;
    }

    /**
     * 标准化元数据
     */
    protected function normalizeMetadata(string $path, Config $config): array
    {
        return [
            'type'      => 'file',
            'path'      => $path,
            'timestamp' => time(),
            'size'      => 0,
        ];
    }
}