package service

import (
	"context"
	"fmt"
	"io"
	"log"
	"mime"
	"mime/multipart"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"github.com/google/uuid"
	"x-agents/server/internal/config"
	"x-agents/server/internal/model"
)

// debugLog 专用调试日志
var debugLog *log.Logger

func init() {
	// 创建调试日志文件
	debugFile, _ := os.OpenFile("logs/debug.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	debugLog = log.New(debugFile, "", log.Ldate|log.Ltime)
}

type UploadService struct {
	cfg *config.Config
	minioClient *minio.Client
}

// UploadResponse 上传响应
type UploadResponse struct {
	Success bool   `json:"success"`
	URL     string `json:"url"`
	FileKey string `json:"fileKey"` // 文件标识，用于删除等操作
	Message string `json:"message"`
}

func NewUploadService(cfg *config.Config) (*UploadService, error) {
	s := &UploadService{cfg: cfg}

	// 如果是 MinIO 模式，初始化 MinIO 客户端
	if cfg.UploadMode == "minio" {
		if cfg.MinIOEndpoint == "" || cfg.MinIOAccessKey == "" || cfg.MinIOSecretKey == "" {
			return nil, fmt.Errorf("MinIO configuration is incomplete")
		}

		client, err := minio.New(cfg.MinIOEndpoint, &minio.Options{
			Creds:  credentials.NewStaticV4(cfg.MinIOAccessKey, cfg.MinIOSecretKey, ""),
			Secure: cfg.MinIOUseSSL,
		})
		if err != nil {
			return nil, fmt.Errorf("failed to create MinIO client: %w", err)
		}

		// 检查 bucket 是否存在，不存在则创建
		exists, err := client.BucketExists(context.Background(), cfg.MinIOBucket)
		if err != nil {
			return nil, fmt.Errorf("failed to check MinIO bucket: %w", err)
		}
		if !exists {
			if err := client.MakeBucket(context.Background(), cfg.MinIOBucket, minio.MakeBucketOptions{}); err != nil {
				return nil, fmt.Errorf("failed to create MinIO bucket: %w", err)
			}
		}

		s.minioClient = client
	}

	return s, nil
}

// Upload 上传文件（使用全局配置）
func (s *UploadService) Upload(file *multipart.FileHeader) (*UploadResponse, error) {
	// 打开文件
	f, err := file.Open()
	if err != nil {
		return &UploadResponse{Success: false, Message: err.Error()}, nil
	}
	defer f.Close()

	// 生成唯一文件名
	ext := filepath.Ext(file.Filename)
	filename := fmt.Sprintf("%s%s", uuid.New().String(), ext)
	fileKey := strings.TrimSuffix(filename, ext)

	// 根据模式选择存储方式
	if s.cfg.UploadMode == "minio" {
		return s.uploadToMinIO(f, filename, fileKey, file.Size)
	}
	return s.uploadToLocal(f, filename, fileKey)
}

// UploadWithConfig 上传文件（使用指定配置）
func (s *UploadService) UploadWithConfig(file *multipart.FileHeader, storageConfig model.StorageConfig) (*UploadResponse, error) {
	// 打开文件
	f, err := file.Open()
	if err != nil {
		return &UploadResponse{Success: false, Message: err.Error()}, nil
	}
	defer f.Close()

	// 生成唯一文件名
	ext := filepath.Ext(file.Filename)
	filename := fmt.Sprintf("%s%s", uuid.New().String(), ext)
	fileKey := strings.TrimSuffix(filename, ext)

	// 根据配置选择存储方式
	if storageConfig.Type == "minio" {
		return s.uploadToMinIOWithConfig(f, filename, fileKey, file.Size, storageConfig)
	}
	// 默认使用本地存储
	return s.uploadToLocal(f, filename, fileKey)
}

// uploadToMinIOWithConfig 使用指定配置上传到 MinIO
func (s *UploadService) uploadToMinIOWithConfig(f multipart.File, filename, fileKey string, size int64, cfg model.StorageConfig) (*UploadResponse, error) {
	debugLog.Printf("[MinIO Upload] 开始上传: endpoint=%s, bucket=%s, filename=%s, size=%d",
		cfg.Endpoint, cfg.Bucket, filename, size)
	debugLog.Printf("[MinIO Upload] MinIO配置详情: endpoint=%s, useSSL=%v, accessKey=%s",
		cfg.Endpoint, cfg.UseSSL, cfg.AccessKeyID)

	// 创建 MinIO 客户端
	client, err := minio.New(cfg.Endpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(cfg.AccessKeyID, cfg.SecretAccessKey, ""),
		Secure: cfg.UseSSL,
	})
	if err != nil {
		debugLog.Printf("[MinIO Upload] 错误: 创建MinIO客户端失败, err=%v", err)
		return &UploadResponse{Success: false, Message: fmt.Sprintf("failed to create MinIO client: %v", err)}, nil
	}
	debugLog.Printf("[MinIO Upload] MinIO客户端创建成功")

	// 检查 bucket 是否存在，不存在则创建
	exists, err := client.BucketExists(context.Background(), cfg.Bucket)
	if err != nil {
		debugLog.Printf("[MinIO Upload] 错误: 检查bucket失败, err=%v", err)
		return &UploadResponse{Success: false, Message: fmt.Sprintf("failed to check bucket: %v", err)}, nil
	}
	debugLog.Printf("[MinIO Upload] Bucket存在检查: exists=%v", exists)

	if !exists {
		debugLog.Printf("[MinIO Upload] 正在创建Bucket: %s", cfg.Bucket)
		if err := client.MakeBucket(context.Background(), cfg.Bucket, minio.MakeBucketOptions{}); err != nil {
			debugLog.Printf("[MinIO Upload] 错误: 创建bucket失败, err=%v", err)
			return &UploadResponse{Success: false, Message: fmt.Sprintf("failed to create bucket: %v", err)}, nil
		}
		debugLog.Printf("[MinIO Upload] Bucket创建成功")
	}

	// 上传文件
	debugLog.Printf("[MinIO Upload] 正在上传文件到MinIO...")
	// 根据文件扩展名获取正确的 Content-Type
	contentType := mime.TypeByExtension(filepath.Ext(filename))
	if contentType == "" {
		contentType = "application/octet-stream"
	}
	_, err = client.PutObject(context.Background(), cfg.Bucket, filename, f, size, minio.PutObjectOptions{
		ContentType: contentType,
	})
	if err != nil {
		debugLog.Printf("[MinIO Upload] 错误: 上传文件失败, err=%v", err)
		return &UploadResponse{Success: false, Message: fmt.Sprintf("MinIO upload failed: %v", err)}, nil
	}
	debugLog.Printf("[MinIO Upload] 文件上传成功")

	// 生成预签名 URL（有效期 24 小时）
	debugLog.Printf("[MinIO Upload] 正在生成预签名URL...")
	presignedURL, err := client.PresignedGetObject(context.Background(), cfg.Bucket, filename, 24*time.Hour, nil)
	if err != nil {
		debugLog.Printf("[MinIO Upload] 错误: 生成预签名URL失败, err=%v", err)
		return &UploadResponse{Success: false, Message: fmt.Sprintf("failed to generate URL: %v", err)}, nil
	}
	debugLog.Printf("[MinIO Upload] 预签名URL生成成功: %s", presignedURL.String())

	return &UploadResponse{
		Success: true,
		URL:     presignedURL.String(),
		FileKey: fileKey,
		Message: "Upload successful",
	}, nil
}

// uploadToMinIO 上传到 MinIO
func (s *UploadService) uploadToMinIO(f multipart.File, filename, fileKey string, size int64) (*UploadResponse, error) {
	// 根据文件扩展名获取正确的 Content-Type
	contentType := mime.TypeByExtension(filepath.Ext(filename))
	if contentType == "" {
		contentType = "application/octet-stream"
	}

	_, err := s.minioClient.PutObject(context.Background(), s.cfg.MinIOBucket, filename, f, size, minio.PutObjectOptions{
		ContentType: contentType,
	})
	if err != nil {
		return &UploadResponse{Success: false, Message: fmt.Sprintf("MinIO upload failed: %v", err)}, nil
	}

	// 生成预签名 URL（有效期 24 小时）
	presignedURL, err := s.minioClient.PresignedGetObject(context.Background(), s.cfg.MinIOBucket, filename, 24*time.Hour, nil)
	if err != nil {
		return &UploadResponse{Success: false, Message: fmt.Sprintf("failed to generate URL: %v", err)}, nil
	}

	return &UploadResponse{
		Success: true,
		URL:     presignedURL.String(),
		FileKey: fileKey,
		Message: "Upload successful",
	}, nil
}

// uploadToLocal 上传到本地
func (s *UploadService) uploadToLocal(f multipart.File, filename, fileKey string) (*UploadResponse, error) {
	// 确保目录存在
	uploadPath := s.cfg.UploadLocalPath
	if err := os.MkdirAll(uploadPath, 0755); err != nil {
		return &UploadResponse{Success: false, Message: fmt.Sprintf("failed to create directory: %v", err)}, nil
	}

	// 创建文件
	dst, err := os.Create(filepath.Join(uploadPath, filename))
	if err != nil {
		return &UploadResponse{Success: false, Message: err.Error()}, nil
	}
	defer dst.Close()

	// 复制内容
	if _, err := io.Copy(dst, f); err != nil {
		return &UploadResponse{Success: false, Message: err.Error()}, nil
	}

	// 生成 URL
	fileURL := fmt.Sprintf("%s/files/%s", s.cfg.ServerBaseURL, filename)

	return &UploadResponse{
		Success: true,
		URL:     fileURL,
		FileKey: fileKey,
		Message: "Upload successful",
	}, nil
}

// DeleteFile 删除文件
func (s *UploadService) DeleteFile(filename string) error {
	if s.cfg.UploadMode == "minio" {
		return s.minioClient.RemoveObject(context.Background(), s.cfg.MinIOBucket, filename, minio.RemoveObjectOptions{})
	}

	// 本地删除
	path := filepath.Join(s.cfg.UploadLocalPath, filename)
	return os.Remove(path)
}

// DeleteFileWithConfig 使用指定配置删除文件
func (s *UploadService) DeleteFileWithConfig(filename string, storageConfig model.StorageConfig) error {
	if storageConfig.Type == "minio" {
		// 创建 MinIO 客户端
		client, err := minio.New(storageConfig.Endpoint, &minio.Options{
			Creds:  credentials.NewStaticV4(storageConfig.AccessKeyID, storageConfig.SecretAccessKey, ""),
			Secure: storageConfig.UseSSL,
		})
		if err != nil {
			debugLog.Printf("[MinIO Delete] 创建客户端失败: %v", err)
			return err
		}
		debugLog.Printf("[MinIO Delete] 删除文件: bucket=%s, filename=%s", storageConfig.Bucket, filename)
		return client.RemoveObject(context.Background(), storageConfig.Bucket, filename, minio.RemoveObjectOptions{})
	}

	// 本地删除
	path := filepath.Join(s.cfg.UploadLocalPath, filename)
	return os.Remove(path)
}

// GetFileURL 获取文件 URL（用于已存在的文件）
func (s *UploadService) GetFileURL(filename string) (string, error) {
	if s.cfg.UploadMode == "minio" {
		presignedURL, err := s.minioClient.PresignedGetObject(context.Background(), s.cfg.MinIOBucket, filename, 24*time.Hour, nil)
		if err != nil {
			return "", err
		}
		return presignedURL.String(), nil
	}

	// 本地文件
	escaped := url.PathEscape(filename)
	return fmt.Sprintf("%s/files/%s", s.cfg.ServerBaseURL, escaped), nil
}

// GetFileContent 获取文件内容（用于代理访问）
func (s *UploadService) GetFileContent(fileKey string) (io.ReadCloser, string, error) {
	if s.cfg.UploadMode == "minio" {
		object, err := s.minioClient.GetObject(context.Background(), s.cfg.MinIOBucket, fileKey, minio.GetObjectOptions{})
		if err != nil {
			return nil, "", err
		}
		// 获取 Content-Type
		stat, err := s.minioClient.StatObject(context.Background(), s.cfg.MinIOBucket, fileKey, minio.StatObjectOptions{})
		if err != nil {
			return nil, "", err
		}
		return object, stat.ContentType, nil
	}

	// 本地文件
	path := filepath.Join(s.cfg.UploadLocalPath, fileKey)
	f, err := os.Open(path)
	if err != nil {
		return nil, "", err
	}
	return f, "application/octet-stream", nil
}

// GetFileContentWithConfig 使用指定配置获取文件内容
func (s *UploadService) GetFileContentWithConfig(fileKey string, storageConfig model.StorageConfig) (io.ReadCloser, string, error) {
	if storageConfig.Type == "minio" {
		// 创建 MinIO 客户端
		client, err := minio.New(storageConfig.Endpoint, &minio.Options{
			Creds:  credentials.NewStaticV4(storageConfig.AccessKeyID, storageConfig.SecretAccessKey, ""),
			Secure: storageConfig.UseSSL,
		})
		if err != nil {
			return nil, "", err
		}

		object, err := client.GetObject(context.Background(), storageConfig.Bucket, fileKey, minio.GetObjectOptions{})
		if err != nil {
			return nil, "", err
		}
		// 获取 Content-Type
		stat, err := client.StatObject(context.Background(), storageConfig.Bucket, fileKey, minio.StatObjectOptions{})
		if err != nil {
			return nil, "", err
		}
		return object, stat.ContentType, nil
	}

	// 本地文件
	path := filepath.Join(s.cfg.UploadLocalPath, fileKey)
	f, err := os.Open(path)
	if err != nil {
		return nil, "", err
	}
	return f, "application/octet-stream", nil
}
