// internal/media/prepare/prepare.go
package prepare

import (
	"bytes"
	"fmt"
	"image"
	"image/gif"
	"image/jpeg"
	"image/png"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/image/webp"
	"go.uber.org/zap"
)

// ImageDimensions represents the dimensions of an image
type ImageDimensions struct {
	Width  int
	Height int
}

// Manager handles media preparation and optimization
type Manager struct {
	logger *zap.Logger
}

// NewManager creates a new preparation manager
func NewManager(logger *zap.Logger) *Manager {
	if logger == nil {
		// Create a default logger if none is provided
		var err error
		logger, err = zap.NewProduction()
		if err != nil {
			// If we can't create a logger, use a no-op logger
			logger = zap.NewNop()
		}
	}
	
	return &Manager{
		logger: logger,
	}
}

// GetMediaDimensions gets the dimensions of an image or video file
func (m *Manager) GetMediaDimensions(filePath string) (*ImageDimensions, error) {
	// Open the file
	file, err := os.Open(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to open file: %w", err)
	}
	defer file.Close()
	
	// Get the file extension
	ext := strings.ToLower(filepath.Ext(filePath))
	
	// Decode the image based on the file extension
	var img image.Image
	
	switch ext {
	case ".jpg", ".jpeg":
		img, err = jpeg.Decode(file)
	case ".png":
		img, err = png.Decode(file)
	case ".gif":
		img, err = gif.Decode(file)
	case ".webp":
		img, err = webp.Decode(file)
	default:
		return nil, fmt.Errorf("unsupported image format: %s", ext)
	}
	
	if err != nil {
		return nil, fmt.Errorf("failed to decode image: %w", err)
	}
	
	// Get the dimensions
	bounds := img.Bounds()
	return &ImageDimensions{
		Width:  bounds.Max.X - bounds.Min.X,
		Height: bounds.Max.Y - bounds.Min.Y,
	}, nil
}

// ResizeImage resizes an image to the specified dimensions
// Returns the path to the resized image
func (m *Manager) ResizeImage(filePath string, maxWidth, maxHeight int) (string, error) {
	// For now, just return the original image
	// In a future update, we can add actual resizing functionality
	return filePath, nil
}

// OptimizeImage optimizes an image for web usage
// Returns the path to the optimized image
func (m *Manager) OptimizeImage(filePath string) (string, error) {
	// For now, just return the original image
	// In a future update, we can add optimization functionality
	return filePath, nil
}

// GetMediaType gets the media type of a file
func (m *Manager) GetMediaType(filePath string) (string, error) {
	// Open the file
	file, err := os.Open(filePath)
	if err != nil {
		return "", fmt.Errorf("failed to open file: %w", err)
	}
	defer file.Close()
	
	// Read the first 512 bytes to detect the content type
	buffer := make([]byte, 512)
	_, err = file.Read(buffer)
	if err != nil && err != io.EOF {
		return "", fmt.Errorf("failed to read file: %w", err)
	}
	
	// Detect the content type
	contentType := detectContentType(buffer)
	
	return contentType, nil
}

// ExtractMetadata extracts metadata from a media file
func (m *Manager) ExtractMetadata(filePath string) (map[string]interface{}, error) {
	// Get the media type
	mediaType, err := m.GetMediaType(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to get media type: %w", err)
	}
	
	// Create the metadata map
	metadata := map[string]interface{}{
		"media_type": mediaType,
	}
	
	// If it's an image, get the dimensions
	if strings.HasPrefix(mediaType, "image/") {
		dims, err := m.GetMediaDimensions(filePath)
		if err != nil {
			m.logger.Warn("Failed to get image dimensions",
				zap.String("filePath", filePath),
				zap.Error(err))
		} else {
			metadata["width"] = dims.Width
			metadata["height"] = dims.Height
			metadata["dimensions"] = fmt.Sprintf("%dx%d", dims.Width, dims.Height)
		}
	}
	
	// Get the file size
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		m.logger.Warn("Failed to get file size",
			zap.String("filePath", filePath),
			zap.Error(err))
	} else {
		metadata["size"] = fileInfo.Size()
	}
	
	return metadata, nil
}

// detectContentType detects the content type of a file
func detectContentType(buffer []byte) string {
	// Try to detect the content type
	contentType := http.DetectContentType(buffer)
	
	// Some additional checks for specific formats
	if contentType == "application/octet-stream" {
		// Check for WebP signature
		if bytes.HasPrefix(buffer, []byte("RIFF")) && bytes.Contains(buffer[8:12], []byte("WEBP")) {
			return "image/webp"
		}
	}
	
	return contentType
}