package service

import (
	"context"
	"path/filepath"
	"strings"
	"time"

	"eslogad-be/internal/contract"

	"github.com/google/uuid"
)

type FileStorage interface {
	Upload(ctx context.Context, bucket, key string, content []byte, contentType string) (string, error)
	EnsureBucket(ctx context.Context, bucket string) error
}

type FileServiceImpl struct {
	storage       FileStorage
	userProcessor UserProcessor
	profileBucket string
	docBucket     string
}

func NewFileService(storage FileStorage, userProcessor UserProcessor, profileBucket, docBucket string) *FileServiceImpl {
	return &FileServiceImpl{storage: storage, userProcessor: userProcessor, profileBucket: profileBucket, docBucket: docBucket}
}

func (s *FileServiceImpl) UploadProfileAvatar(ctx context.Context, userID uuid.UUID, filename string, content []byte, contentType string) (string, error) {
	if err := s.storage.EnsureBucket(ctx, s.profileBucket); err != nil {
		return "", err
	}
	ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(filename), "."))
	if ext := mimeExtFromContentType(contentType); ext != "" {
		ext = ext
	}
	key := buildObjectKey("profile", userID, ext)
	url, err := s.storage.Upload(ctx, s.profileBucket, key, content, contentType)
	if err != nil {
		return "", err
	}

	_, _ = s.userProcessor.UpdateUserProfile(ctx, userID, &contract.UpdateUserProfileRequest{AvatarURL: &url})
	return url, nil
}

func (s *FileServiceImpl) UploadDocument(ctx context.Context, userID uuid.UUID, filename string, content []byte, contentType string) (string, string, error) {
	if err := s.storage.EnsureBucket(ctx, s.docBucket); err != nil {
		return "", "", err
	}
	ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(filename), "."))
	if ext := mimeExtFromContentType(contentType); ext != "" {
		ext = ext
	}
	key := buildObjectKey("documents", userID, ext)
	url, err := s.storage.Upload(ctx, s.docBucket, key, content, contentType)
	if err != nil {
		return "", "", err
	}
	return url, key, nil
}

func buildObjectKey(prefix string, userID uuid.UUID, ext string) string {
	now := time.Now().UTC()
	parts := []string{
		prefix,
		userID.String(),
		now.Format("2006/01/02"),
		uuid.New().String(),
	}
	key := strings.Join(parts, "/")
	if ext != "" {
		key += "." + ext
	}
	return key
}

func mimeExtFromContentType(ct string) string {
	switch strings.ToLower(ct) {
	case "image/jpeg", "image/jpg":
		return "jpg"
	case "image/png":
		return "png"
	case "image/webp":
		return "webp"
	case "application/pdf":
		return "pdf"
	default:
		return ""
	}
}
