package oss_core

import (
	"context"
	"fmt"
	"io"
	"mime/multipart"
	"path/filepath"
	"strings"
	"time"

	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"sundynix-micro-go/app/file/rpc/file"
	"sundynix-micro-go/common/utils/hash"
)

type MinioUploader struct {
	client *minio.Client
	config *file.StorageConfigInfo
}

func NewMinioUploader(conf *file.StorageConfigInfo) (Uploader, error) {
	// 判断如果是 https 或者是类似云服务，可以根据 endpoint 后缀猜测 secure
	useSSL := strings.HasPrefix(conf.Endpoint, "https://") || strings.Contains(conf.Endpoint, "aliyuncs.com") || conf.Endpoint == "oss-cn-hangzhou.aliyuncs.com" // 这里只是示例
	if strings.HasPrefix(conf.Endpoint, "http://") || strings.HasPrefix(conf.Endpoint, "https://") {
		// 移除协议头给 minio 客户端
		conf.Endpoint = strings.TrimPrefix(conf.Endpoint, "http://")
		conf.Endpoint = strings.TrimPrefix(conf.Endpoint, "https://")
	} else {
		// 默认非 SSL
		useSSL = false
	}

	client, err := minio.New(conf.Endpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(conf.AccessKeyId, conf.AccessKeySecret, ""),
		Secure: useSSL,
	})
	if err != nil {
		return nil, err
	}

	// 这里可以加上检查 bucket
	return &MinioUploader{
		client: client,
		config: conf,
	}, nil
}

func (m *MinioUploader) UploadFile(ctx context.Context, file multipart.File, fileHeader *multipart.FileHeader) (string, string, error) {
	// 直接重置文件指针（保险起见）
	file.Seek(0, 0)

	ext := filepath.Ext(fileHeader.Filename)
	filename := hash.MD5([]byte(strings.TrimSuffix(fileHeader.Filename, ext))) + ext
	timestr := fmt.Sprintf("%d", time.Now().UnixMicro())
	objectKey := time.Now().Format("2006-01-02") + "/" + timestr + "-" + filename

	bucketName := m.config.BucketName

	// 直接执行 PutObject（流式上传，不再全部读入内存）
	info, err := m.client.PutObject(ctx, bucketName, objectKey, file, fileHeader.Size, minio.PutObjectOptions{
		ContentType: "application/octet-stream",
	})

	if err != nil {
		// 如果是因为 bucket 不存在，则尝试创建并重试
		if minio.ToErrorResponse(err).Code == "NoSuchBucket" {
			m.client.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{})
			// 重置文件流位置，准备重试
			file.Seek(0, 0)
			info, err = m.client.PutObject(ctx, bucketName, objectKey, file, fileHeader.Size, minio.PutObjectOptions{
				ContentType: "application/octet-stream",
			})
		}
		if err != nil {
			return "", "", fmt.Errorf("上传Minio失败: %v", err)
		}
	}

	url := m.config.BucketUrl + "/" + info.Key
	return url, info.Key, nil
}

func (m *MinioUploader) DeleteFile(ctx context.Context, key string) error {
	return m.client.RemoveObject(ctx, m.config.BucketName, key, minio.RemoveObjectOptions{})
}

func (m *MinioUploader) DownloadFile(ctx context.Context, key string) (io.ReadCloser, error) {
	obj, err := m.client.GetObject(ctx, m.config.BucketName, key, minio.GetObjectOptions{})
	if err != nil {
		return nil, err
	}
	return obj, nil
}
