package com.example.dateplanner.services;

import com.example.dateplanner.utils.InputStreamCollector;
import io.minio.*;
import io.minio.errors.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.util.Objects;
import java.util.UUID;

@Slf4j
@Service
public class MinioService {

    private final MinioClient minioClient;
    private final String bucket;

    @SneakyThrows
    public MinioService(MinioClient minioClient, @Value("${minio.bucket}") String bucket) {
        this.minioClient = minioClient;
        this.bucket = bucket;
        if (!this.minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build())) {
            this.minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
            log.info("MinIO bucket '{}' created", bucket);
        }
    }

    public Mono<String> uploadImage(FilePart file) {
        return file.content()
                .subscribeOn(Schedulers.boundedElastic())
                .reduce(new InputStreamCollector(),
                        (collector, dataBuffer) -> collector.collectInputStream(dataBuffer.asInputStream()))
                .flatMap(collector -> {
                    long start = System.currentTimeMillis();
                    String extension = FilenameUtils.getExtension(file.filename());
                    String objectName = UUID.randomUUID() + (extension.isEmpty() ? ".jpg" : "." + extension);
                    try {
                        String contentType = Objects.requireNonNull(file.headers().getContentType()).toString();
                        PutObjectArgs args = PutObjectArgs.builder()
                                .bucket(bucket)
                                .object(objectName)
                                .contentType(contentType)
                                .stream(collector.getStream(), collector.getTotalSize(), -1)
                                .build();
                        minioClient.putObject(args);
                        collector.closeStream();
                        log.info("MinIO upload '{}' in {} ms", objectName, System.currentTimeMillis() - start);
                        return Mono.just("/" + bucket + "/" + objectName);
                    } catch (Exception e) {
                        log.error("MinIO upload failed: {}", e.getMessage());
                        return Mono.error(new RuntimeException(e));
                    }
                });
    }
}
