package service

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

	"github.com/google/uuid"
)

// UploadService 文件上传服务接口
type UploadService interface {
	// 上传音频文件
	UploadAudio(file *multipart.FileHeader) (*UploadResult, error)
	// 上传图片文件
	UploadImage(file *multipart.FileHeader) (*UploadResult, error)
	// 删除文件
	DeleteFile(filePath string) error
	// 获取文件URL
	GetFileURL(filePath string) string
}

type uploadService struct {
	uploadDir string
	baseURL   string
}

// UploadResult 上传结果
type UploadResult struct {
	FileName    string `json:"file_name"`
	FilePath    string `json:"file_path"`
	FileURL     string `json:"file_url"`
	FileSize    int64  `json:"file_size"`
	ContentType string `json:"content_type"`
}

// NewUploadService 创建文件上传服务实例
func NewUploadService(uploadDir, baseURL string) UploadService {
	// 确保上传目录存在
	os.MkdirAll(uploadDir, 0755)
	os.MkdirAll(filepath.Join(uploadDir, "audio"), 0755)
	os.MkdirAll(filepath.Join(uploadDir, "images"), 0755)

	return &uploadService{
		uploadDir: uploadDir,
		baseURL:   baseURL,
	}
}

// 允许的文件类型
var (
	allowedAudioTypes = map[string]bool{
		"audio/mpeg":     true, // mp3
		"audio/wav":      true, // wav
		"audio/mp4":      true, // m4a
		"audio/webm":     true, // webm
		"audio/ogg":      true, // ogg
	}

	allowedImageTypes = map[string]bool{
		"image/jpeg": true, // jpg, jpeg
		"image/png":  true, // png
		"image/gif":  true, // gif
		"image/webp": true, // webp
	}

	// 文件大小限制（字节）
	maxAudioSize = 50 * 1024 * 1024  // 50MB
	maxImageSize = 10 * 1024 * 1024  // 10MB
)

// UploadAudio 上传音频文件
func (s *uploadService) UploadAudio(file *multipart.FileHeader) (*UploadResult, error) {
	// 检查文件大小
	if file.Size > int64(maxAudioSize) {
		return nil, fmt.Errorf("audio file too large, max size is %d MB", maxAudioSize/(1024*1024))
	}

	// 检查文件类型
	contentType := file.Header.Get("Content-Type")
	if !allowedAudioTypes[contentType] {
		return nil, fmt.Errorf("unsupported audio format: %s", contentType)
	}

	// 生成唯一文件名
	ext := filepath.Ext(file.Filename)
	fileName := fmt.Sprintf("%s_%d%s", uuid.New().String(), time.Now().Unix(), ext)
	relativePath := filepath.Join("audio", fileName)
	fullPath := filepath.Join(s.uploadDir, relativePath)

	// 保存文件
	if err := s.saveFile(file, fullPath); err != nil {
		return nil, fmt.Errorf("failed to save audio file: %w", err)
	}

	return &UploadResult{
		FileName:    fileName,
		FilePath:    relativePath,
		FileURL:     s.GetFileURL(relativePath),
		FileSize:    file.Size,
		ContentType: contentType,
	}, nil
}

// UploadImage 上传图片文件
func (s *uploadService) UploadImage(file *multipart.FileHeader) (*UploadResult, error) {
	// 检查文件大小
	if file.Size > int64(maxImageSize) {
		return nil, fmt.Errorf("image file too large, max size is %d MB", maxImageSize/(1024*1024))
	}

	// 检查文件类型
	contentType := file.Header.Get("Content-Type")
	if !allowedImageTypes[contentType] {
		return nil, fmt.Errorf("unsupported image format: %s", contentType)
	}

	// 生成唯一文件名
	ext := filepath.Ext(file.Filename)
	fileName := fmt.Sprintf("%s_%d%s", uuid.New().String(), time.Now().Unix(), ext)
	relativePath := filepath.Join("images", fileName)
	fullPath := filepath.Join(s.uploadDir, relativePath)

	// 保存文件
	if err := s.saveFile(file, fullPath); err != nil {
		return nil, fmt.Errorf("failed to save image file: %w", err)
	}

	return &UploadResult{
		FileName:    fileName,
		FilePath:    relativePath,
		FileURL:     s.GetFileURL(relativePath),
		FileSize:    file.Size,
		ContentType: contentType,
	}, nil
}

// saveFile 保存文件到磁盘
func (s *uploadService) saveFile(fileHeader *multipart.FileHeader, destPath string) error {
	// 确保目录存在
	dir := filepath.Dir(destPath)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return fmt.Errorf("failed to create directory: %w", err)
	}

	// 打开上传的文件
	src, err := fileHeader.Open()
	if err != nil {
		return fmt.Errorf("failed to open uploaded file: %w", err)
	}
	defer src.Close()

	// 创建目标文件
	dst, err := os.Create(destPath)
	if err != nil {
		return fmt.Errorf("failed to create destination file: %w", err)
	}
	defer dst.Close()

	// 复制文件内容
	_, err = io.Copy(dst, src)
	if err != nil {
		return fmt.Errorf("failed to copy file content: %w", err)
	}

	return nil
}

// DeleteFile 删除文件
func (s *uploadService) DeleteFile(filePath string) error {
	// 安全检查：确保文件路径在上传目录内
	if !strings.HasPrefix(filePath, s.uploadDir) {
		fullPath := filepath.Join(s.uploadDir, filePath)
		filePath = fullPath
	}

	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		return fmt.Errorf("file does not exist: %s", filePath)
	}

	// 删除文件
	if err := os.Remove(filePath); err != nil {
		return fmt.Errorf("failed to delete file: %w", err)
	}

	return nil
}

// GetFileURL 获取文件URL
func (s *uploadService) GetFileURL(filePath string) string {
	// 清理路径分隔符
	cleanPath := strings.ReplaceAll(filePath, "\\", "/")
	return fmt.Sprintf("%s/uploads/%s", s.baseURL, cleanPath)
}

// ValidateFileType 验证文件类型
func ValidateFileType(filename string, allowedTypes map[string]bool) bool {
	ext := strings.ToLower(filepath.Ext(filename))
	switch ext {
	case ".mp3":
		return allowedTypes["audio/mpeg"]
	case ".wav":
		return allowedTypes["audio/wav"]
	case ".m4a":
		return allowedTypes["audio/mp4"]
	case ".webm":
		return allowedTypes["audio/webm"]
	case ".ogg":
		return allowedTypes["audio/ogg"]
	case ".jpg", ".jpeg":
		return allowedTypes["image/jpeg"]
	case ".png":
		return allowedTypes["image/png"]
	case ".gif":
		return allowedTypes["image/gif"]
	case ".webp":
		return allowedTypes["image/webp"]
	default:
		return false
	}
}