package com.ai.trackwalker.storage;

import com.ai.trackwalker.config.RailProperties;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.security.MessageDigest;
import java.util.HexFormat;

@Service
public class ModelArtifactStorageService {
    private static final Logger log = LoggerFactory.getLogger(ModelArtifactStorageService.class);

    private final RailProperties properties;
    private final MinioClient minioClient;
    private volatile boolean available;

    public ModelArtifactStorageService(RailProperties properties) {
        this.properties = properties;
        this.minioClient = MinioClient.builder()
                .endpoint(properties.getStorage().getMinioEndpoint())
                .credentials(properties.getStorage().getMinioAccessKey(), properties.getStorage().getMinioSecretKey())
                .build();
    }

    @PostConstruct
    public void initialize() {
        try {
            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket()).build())) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket()).build());
            }
            available = true;
        } catch (Exception e) {
            available = false;
            log.warn("模型制品库暂不可用: {}", e.getMessage());
        }
    }

    public StoredArtifact store(String objectKey, MultipartFile file) {
        if (!available) {
            initialize();
        }
        if (!available) {
            throw new IllegalStateException("模型制品库不可用，请检查 MinIO 服务和凭据");
        }
        String safeKey = normalizeObjectKey(objectKey);
        String contentType = file.getContentType() == null ? "application/octet-stream" : file.getContentType();
        String sha256 = sha256(file);
        try (InputStream stream = file.getInputStream()) {
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucket())
                    .object(safeKey)
                    .stream(stream, file.getSize(), -1)
                    .contentType(contentType)
                    .build());
            return new StoredArtifact(safeKey, "s3://" + bucket() + "/" + safeKey,
                    sha256, file.getSize(), contentType);
        } catch (Exception e) {
            throw new IllegalStateException("写入模型制品库失败", e);
        }
    }

    public void delete(String objectKey) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucket()).object(normalizeObjectKey(objectKey)).build());
        } catch (Exception e) {
            throw new IllegalStateException("删除模型制品库对象失败", e);
        }
    }

    public String bucket() {
        String configured = properties.getStorage().getArtifactBucket();
        return configured == null || configured.isBlank() ? "rail-model-artifacts" : configured;
    }

    public boolean isAvailable() {
        return available;
    }

    static String normalizeObjectKey(String value) {
        String normalized = value == null ? "" : value.replace('\\', '/');
        while (normalized.startsWith("/")) {
            normalized = normalized.substring(1);
        }
        if (normalized.isBlank() || normalized.contains("../") || normalized.equals("..")) {
            throw new IllegalArgumentException("非法模型制品对象路径");
        }
        return normalized;
    }

    private String sha256(MultipartFile file) {
        try (InputStream stream = file.getInputStream()) {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] buffer = new byte[1024 * 1024];
            int read;
            while ((read = stream.read(buffer)) != -1) {
                digest.update(buffer, 0, read);
            }
            return HexFormat.of().formatHex(digest.digest());
        } catch (Exception e) {
            throw new IllegalStateException("计算模型制品 SHA-256 失败", e);
        }
    }

    public record StoredArtifact(
            String objectKey,
            String storageUrl,
            String sha256,
            long sizeBytes,
            String contentType
    ) {
    }
}
