package cn.reghao.bnt.web.devops.aliyun.service;

import cn.reghao.bnt.web.devops.aliyun.db.repository.AliyunAccountRepository;
import cn.reghao.bnt.web.devops.aliyun.model.po.AliyunAccount;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author reghao
 * @date 2024-08-30 16:13:38
 */
@Slf4j
@Component
public class AliyunOss {
    private OSS ossClient;
    private final AliyunAccountRepository aliyunAccountRepository;
    private String bucketName;

    public AliyunOss(AliyunAccountRepository aliyunAccountRepository) {
        this.aliyunAccountRepository = aliyunAccountRepository;
        this.bucketName = "";
    }

    @PostConstruct
    public void initOssClient() {
        AliyunAccount aliyunAccount = aliyunAccountRepository.findByType("oss");
        String endpoint = aliyunAccount.getEndpoint();
        String accessKeyId = aliyunAccount.getAccessKeyId();
        String accessKeySecret = aliyunAccount.getAccessKeySecret();
        this.ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    }

    public void uploadObject(String bucketName, String objectName, File file) throws IOException {
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, file);
        /*ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setObjectAcl(CannedAccessControlList.PublicRead);
        putObjectRequest.setMetadata(objectMetadata);*/
        ossClient.putObject(putObjectRequest);
    }

    /**
     * 将指定目录中的所有文件上传到 oss 根目录
     *
     * @param
     * @return
     * @date 2025-06-05 16:05:45
     */
    public List<String> uploadDir(String bucketName, String localDir) {
        List<String> failedList = new ArrayList<>();
        try {
            walkDir(bucketName, Path.of(localDir), failedList);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return failedList;
    }

    private void walkDir(String bucketName, Path path, List<String> failedList) throws IOException {
        final String BLANK = "";
        if (path.toString().equals(BLANK)) {
            throw new IOException("CAN NOT specify a BLANK path");
        }

        Files.walkFileTree(path, new FileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                uploadObject(bucketName, file.toFile(), path.toString(), failedList);
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }
        });
    }

    private void uploadObject(String bucketName, File file, String baseDir, List<String> failedList) {
        String absolutePath = file.getAbsolutePath();
        String objectName = absolutePath.replace(baseDir + "/", "");
        try {
            uploadObject(bucketName, objectName, file);
        } catch (IOException e) {
            e.printStackTrace();
            failedList.add(file.getAbsolutePath());
        }
    }

    public void deleteObject(String bucketName, String objectName) {
        ossClient.deleteObject(bucketName, objectName);
    }

    public void deleteObjects(String bucketName, String prefix) {
        // 删除目录及目录下的所有文件
        String nextMarker = null;
        ObjectListing objectListing = null;
        do {
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName)
                    .withPrefix(prefix)
                    .withMarker(nextMarker);
            objectListing = ossClient.listObjects(listObjectsRequest);
            if (objectListing.getObjectSummaries().size() > 0) {
                List<String> keys = new ArrayList<>();
                for (OSSObjectSummary s : objectListing.getObjectSummaries()) {
                    log.info("key name in bucket {} -> {}", bucketName, s.getKey());
                    keys.add(s.getKey());
                }

                /*DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName).withKeys(keys).withEncodingType("url");
                DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(deleteObjectsRequest);
                List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
                for(String obj : deletedObjects) {
                    String deleteObj =  URLDecoder.decode(obj, StandardCharsets.UTF_8);
                    System.out.println(deleteObj);
                    log.info("delete object {} in bucket {}", deleteObj, bucketName);
                }*/
            }

            nextMarker = objectListing.getNextMarker();
        } while (objectListing.isTruncated());
    }

    public String getSignedUrl(String objectName) {
        int expireSecond = 3600;
        long timestamp = System.currentTimeMillis() + expireSecond*1000L;
        Date expiration = new Date(timestamp);
        URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
        return url.toString();
    }

    public void close() {
        ossClient.shutdown();
    }
}
