package com.caliverse.admin.domain.service;

import com.caliverse.admin.domain.entity.log.LogStatus;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.common.utils.FileUtils;
import com.caliverse.admin.mongodb.service.BusinessLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Optional;
import java.util.UUID;

@Slf4j
@Service
@ConditionalOnProperty(name = "amazon.s3.enabled", havingValue = "true")
@RequiredArgsConstructor
public class S3Service {
    @Autowired(required = false)
    private final S3Client s3Client;

    private final BusinessLogService businessLogService;
    private final FileUtils fileUtils;

    @Value("${amazon.s3.bucket-name}")
    private String bucketName;

    @Value("${amazon.aws.region}")
    private String region;

    @Value("${amazon.s3.cloud-front}")
    private String cloudFrontUrl;

    @Value("${spring.profiles.active}")
    private String activeProfile;

    public Optional<GetObjectAttributesResponse> getObjectMetadata(String key) {
        try {
            GetObjectAttributesRequest request = GetObjectAttributesRequest.builder()
                    .bucket(bucketName)
                    .key(key)
                    .build();

            GetObjectAttributesResponse response = s3Client.getObjectAttributes(request);
            return Optional.of(response);
        } catch (S3Exception e) {
            log.error("Error retrieving object metadata: {}", e.getMessage());
            return Optional.empty();
        }
    }

    public String uploadFile(File file, String directoryName, String contentType) throws IOException, S3Exception {
        String fileName = CommonUtils.getCreateGuId() + "-" + file.getName();

        // S3 객체 키 (경로 + 파일명)
        String objectKey = String.format("%s/%s/%s", activeProfile, directoryName, fileName);

        try {

            PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                    .bucket(bucketName)
                    .key(objectKey)
                    .contentType(contentType)
                    .build();

            // 파일 업로드
            PutObjectResponse response = s3Client.putObject(
                    putObjectRequest,
                    RequestBody.fromBytes(Files.readAllBytes(file.toPath()))
            );

            log.info("Uploaded S3 object with key: {}", objectKey);

            if(response.sdkHttpResponse().isSuccessful()){
                businessLogService.logS3(
                        LogStatus.SUCCESS,
                        "",
                        CommonUtils.getAdmin().getId().toString(),
                        CommonUtils.getClientIp(),
                        bucketName,
                        objectKey,
                        file.length(),
                        fileUtils.getContentType(file.getName())
                );
            }

            return cloudFrontUrl + objectKey;
        }catch (S3Exception | IOException e) {
            throw e;
        }
    }

    public void deleteFile(String fileUrl) {
        String objectKey;

        if (fileUrl.startsWith(cloudFrontUrl)) {
            objectKey = fileUrl.substring(cloudFrontUrl.length());
        } else {
            objectKey = "";
        }

        if(objectKey.isEmpty()){
            log.warn("Deleting S3 Fail: {}", fileUrl);
            return;
        }

        log.info("Deleting S3 object with key: {}", objectKey);

        s3Client.deleteObject(builder -> builder
                .bucket(bucketName)
                .key(objectKey)
                .build());
    }
}
