package service

import (
	"context"
	"fmt"
	"math/rand"
	"path/filepath"
	"strings"
	"time"

	"netidhub-saas-be/config/config"

	"github.com/gofiber/fiber/v2"
	"github.com/minio/minio-go/v7"
	"github.com/rs/zerolog"
)

// ClientLogoUploadService handles client logo uploads to MinIO
type ClientLogoUploadService struct {
	MinioStorage *config.MinioStorage
	Log          zerolog.Logger
}

// NewClientLogoUploadService creates a new client logo upload service
func NewClientLogoUploadService(minioStorage *config.MinioStorage, log zerolog.Logger) *ClientLogoUploadService {
	return &ClientLogoUploadService{
		MinioStorage: minioStorage,
		Log:          log,
	}
}

// UploadLogo uploads client logo to MinIO and returns the image path
func (s *ClientLogoUploadService) UploadLogo(c *fiber.Ctx, clientId string) (string, error) {
	// Get the uploaded file
	file, err := c.FormFile("logo")
	if err != nil {
		return "", fmt.Errorf("failed to get uploaded file: %w", err)
	}

	// Validate file type
	if !s.isValidImageType(file.Filename) {
		return "", fmt.Errorf("invalid file type. Only jpg, jpeg, png, gif, webp are allowed")
	}

	// Validate file size (max 5MB)
	const maxSize = 5 * 1024 * 1024 // 5MB
	if file.Size > maxSize {
		return "", fmt.Errorf("file size too large. Maximum size is 5MB")
	}

	// Create MinIO connection
	minioClient, err := s.MinioStorage.ConnectMinio()
	if err != nil {
		return "", fmt.Errorf("failed to connect to MinIO: %w", err)
	}

	bucketName := s.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName

	// Generate unique filename
	filename := s.generateUniqueFilename(file.Filename)
	objectName := fmt.Sprintf("clients/logos/%s/%s", clientId, filename)

	// Open file
	src, err := file.Open()
	if err != nil {
		return "", fmt.Errorf("failed to open uploaded file: %w", err)
	}
	defer src.Close()

	// Upload to MinIO
	_, err = minioClient.PutObject(
		context.Background(),
		bucketName,
		objectName,
		src,
		file.Size,
		minio.PutObjectOptions{
			ContentType: s.getContentType(file.Filename),
		},
	)
	if err != nil {
		return "", fmt.Errorf("failed to upload file to MinIO: %w", err)
	}

	s.Log.Info().
		Str("clientId", clientId).
		Str("filename", filename).
		Str("objectName", objectName).
		Int64("fileSize", file.Size).
		Msg("Client logo uploaded successfully")

	return objectName, nil
}

// DeleteLogo deletes client logo from MinIO
func (s *ClientLogoUploadService) DeleteLogo(clientId, imagePath string) error {
	if imagePath == "" {
		return nil // Nothing to delete
	}

	// Create MinIO connection
	minioClient, err := s.MinioStorage.ConnectMinio()
	if err != nil {
		return fmt.Errorf("failed to connect to MinIO: %w", err)
	}

	bucketName := s.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName

	// Delete from MinIO
	err = minioClient.RemoveObject(context.Background(), bucketName, imagePath, minio.RemoveObjectOptions{})
	if err != nil {
		return fmt.Errorf("failed to delete file from MinIO: %w", err)
	}

	s.Log.Info().
		Str("clientId", clientId).
		Str("imagePath", imagePath).
		Msg("Client logo deleted successfully")

	return nil
}

// GetLogoURL generates a presigned URL for the logo
func (s *ClientLogoUploadService) GetLogoURL(imagePath string, expiry time.Duration) (string, error) {
	if imagePath == "" {
		return "", nil
	}

	// Create MinIO connection
	minioClient, err := s.MinioStorage.ConnectMinio()
	if err != nil {
		return "", fmt.Errorf("failed to connect to MinIO: %w", err)
	}

	bucketName := s.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName

	// Generate presigned URL
	url, err := minioClient.PresignedGetObject(context.Background(), bucketName, imagePath, expiry, nil)
	if err != nil {
		return "", fmt.Errorf("failed to generate presigned URL: %w", err)
	}

	return url.String(), nil
}

// isValidImageType checks if the file extension is a valid image type
func (s *ClientLogoUploadService) isValidImageType(filename string) bool {
	ext := strings.ToLower(filepath.Ext(filename))
	validExts := []string{".jpg", ".jpeg", ".png", ".gif", ".webp"}

	for _, validExt := range validExts {
		if ext == validExt {
			return true
		}
	}
	return false
}

// generateUniqueFilename generates a unique filename with timestamp and random number
func (s *ClientLogoUploadService) generateUniqueFilename(originalFilename string) string {
	ext := filepath.Ext(originalFilename)
	nameWithoutExt := strings.TrimSuffix(filepath.Base(originalFilename), ext)

	// Clean filename (remove spaces and special characters)
	nameWithoutExt = strings.ReplaceAll(nameWithoutExt, " ", "_")
	nameWithoutExt = strings.ReplaceAll(nameWithoutExt, "-", "_")

	// Generate unique suffix
	now := time.Now()
	rand.Seed(now.UnixNano())
	randomNum := rand.Intn(1000000)

	// Format: originalname_timestamp_random.ext
	return fmt.Sprintf("%s_%d_%d%s",
		nameWithoutExt,
		now.Unix(),
		randomNum,
		ext)
}

// getContentType returns the MIME type based on file extension
func (s *ClientLogoUploadService) getContentType(filename string) string {
	ext := strings.ToLower(filepath.Ext(filename))
	switch ext {
	case ".jpg", ".jpeg":
		return "image/jpeg"
	case ".png":
		return "image/png"
	case ".gif":
		return "image/gif"
	case ".webp":
		return "image/webp"
	default:
		return "application/octet-stream"
	}
}
