package service

import (
	"context"
	"github.com/minio/minio-go/v7"
	"github.com/rs/zerolog"
	"io"
	"time"
)

// AsyncUploader menangani proses upload secara asynchronous
type UploadService interface {
	UploadFile(ctx context.Context, minioClient *minio.Client, uploadID string, reader io.Reader, bucketName string, objectName string, size int64, contentType string) error
}

type uploadService struct {
	uploadManager UploadManager
	Log           zerolog.Logger
}

func NewUploadService(uploadManager UploadManager, log zerolog.Logger) UploadService {
	return &uploadService{
		uploadManager: uploadManager,
		Log:           log,
	}
}

func (u *uploadService) UploadFile(ctx context.Context, minioClient *minio.Client, uploadID string, reader io.Reader, bucketName string, objectName string, size int64, contentType string) error {
	status := &UploadStatus{
		FileName:   objectName,
		Size:       size,
		Progress:   0,
		Status:     "uploading",
		ObjectName: objectName,
		BucketName: bucketName,
		StartTime:  time.Now(),
	}

	u.uploadManager.Add(uploadID, status)

	u.Log.Info().Str("timestamp", time.Now().
		Format(time.RFC3339)).Str("Service:Resource", "UploadService::UploadFile").
		Interface("add status", status).Msg("")

	// Upload ke Minio
	_, err := minioClient.PutObject(
		ctx,
		bucketName,
		objectName,
		reader,
		size,
		minio.PutObjectOptions{
			ContentType: contentType,
			PartSize:    10 * 1024 * 1024, // 10MB part size
		},
	)

	if err != nil {
		u.uploadManager.UpdateStatus(uploadID, "error", err)

		u.Log.Info().Str("timestamp", time.Now().
			Format(time.RFC3339)).Str("Service:Resource", "UploadService::UploadFile").
			Interface("error when upload", err).Msg("")
	}

	u.uploadManager.UpdateStatus(uploadID, "completed", nil)
	return nil
}

//func (au *UploadService) UploadFile() {
//	// Buat context dengan timeout
//	ctx, cancel := context.WithTimeout(au.ctx, 30*time.Minute)
//	defer cancel()
//
//	// Buat reader dari byte slice
//	reader := bytes.NewReader(au.fileData)
//	pipeReader, pipeWriter := io.Pipe()
//
//	au.progressMap.Store(au.uploadID, 0.0)
//
//	// Start goroutine to read from reader and write to pipe
//	go func() {
//		defer pipeWriter.Close()
//		buf := make([]byte, au.partSize)
//
//		totalParts := int(reader.Size() / au.partSize)
//		if reader.Size()%au.partSize != 0 {
//			totalParts++
//		}
//
//		for i := 0; i < totalParts; i++ {
//			n, err := reader.Read(buf)
//			if err != nil && err != io.EOF {
//				log.Println("Error reading file:", err)
//				return
//			}
//
//			if _, err := pipeWriter.Write(buf[:n]); err != nil {
//				log.Println("Error writing to pipe:", err)
//				return
//			}
//
//			progress := float64(i+1) / float64(totalParts) * 100
//			au.progressMap.Store(au.uploadID, progress)
//			au.uploadManager.UpdateProgress(au.uploadID, int(progress))
//		}
//	}()
//
//	// Upload ke Minio
//	_, err := au.minioClient.PutObject(
//		ctx,
//		au.bucketName,
//		au.objectName,
//		pipeReader,
//		reader.Size(),
//		minio.PutObjectOptions{
//			ContentType: au.contentType,
//			PartSize:    10 * 1024 * 1024, // 10MB part size
//		},
//	)
//
//	if err != nil {
//		log.Println("Error uploading file:", err)
//		au.progressMap.Store(au.uploadID, "error")
//		return
//	}
//
//	fmt.Printf("Uploading process for %s", au.objectName)
//
//	if err != nil {
//		uploadManager.UpdateStatus(au.uploadID, "error", err)
//		fmt.Printf("Upload error for %s: %v\n", au.objectName, err)
//		return
//	}
//
//	au.progressMap.Store(au.uploadID, 100)
//	au.uploadManager.UpdateProgress(au.uploadID, 100)
//	au.uploadManager.UpdateStatus(au.uploadID, "completed", nil)
//}
