package com.njzscloud.supervisory.biz.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.core.tuple.Tuple2;
import com.njzscloud.common.mp.support.PageParam;
import com.njzscloud.common.mp.support.PageResult;
import com.njzscloud.common.security.support.UserDetail;
import com.njzscloud.common.security.util.SecurityUtil;
import com.njzscloud.supervisory.biz.mapper.BizAuditConfigMapper;
import com.njzscloud.supervisory.biz.pojo.entity.BizAuditConfigEntity;
import com.njzscloud.supervisory.biz.pojo.result.SearchAuditConfigResult;
import com.njzscloud.supervisory.config.AppProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.njzscloud.supervisory.constant.Constant.ROLE_JG;

/**
 * 审核配置
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BizAuditConfigService extends ServiceImpl<BizAuditConfigMapper, BizAuditConfigEntity> implements IService<BizAuditConfigEntity> {
    private final AppProperties appProperties;
    // 1. 配置线程池：核心线程数100，最大线程数100（控制并发量）
    // 队列使用SynchronousQueue，避免任务堆积（若任务过多可改用有界队列）
    ThreadPoolExecutor executor = null;
    OSS oss1 = null;
    OSS oss2 = null;
    AtomicInteger t = new AtomicInteger();
    AtomicInteger s = new AtomicInteger();
    AtomicInteger e = new AtomicInteger();

    public static String uploadFile(OSS oss, String objectName, String contentType, InputStream inputStream) {
        ObjectMetadata objectMetadata = new ObjectMetadata();
        if (StrUtil.isNotBlank(contentType)) objectMetadata.setContentType(contentType);
        oss.putObject("czxcsy-cdn", objectName, inputStream, objectMetadata);
        return "/" + "czxcsy-cdn" + "/" + objectName;
    }

    public static Tuple2<InputStream, String> obtainFile(OSS oss, String bucketName, String objectName) {
        OSSObject response = oss.getObject(new GetObjectRequest(bucketName, objectName));
        ObjectMetadata objectMetadata = response.getObjectMetadata();
        String contentType = objectMetadata.getContentType();
        InputStream objectContent = response.getObjectContent();
        return Tuple2.create(objectContent, contentType);
    }

    /**
     * 新增
     */
    @Transactional(rollbackFor = Exception.class)
    public void add(BizAuditConfigEntity bizAuditConfigEntity) {
        AppProperties.DefaultPlace defaultPlace = appProperties.getDefaultPlace();
        bizAuditConfigEntity.setProvince(defaultPlace.getProvince())
                .setCity(defaultPlace.getCity())
                .setProvinceName(defaultPlace.getProvinceName())
                .setCityName(defaultPlace.getCityName());


        String area = bizAuditConfigEntity.getArea();
        Assert.isTrue(StrUtil.isNotBlank(area), () -> Exceptions.clierr("区县不能为空"));
        String areaName = baseMapper.getAreaName(area);
        Assert.isTrue(StrUtil.isNotBlank(areaName), () -> Exceptions.clierr("区县名称不能为空"));
        bizAuditConfigEntity.setAreaName(areaName);

        String areaRole = bizAuditConfigEntity.getAreaRole();
        if (StrUtil.isNotBlank(areaRole)) {
            Assert.isTrue(StrUtil.isNotBlank(bizAuditConfigEntity.getCityRole()), () -> Exceptions.clierr("市级审核员不能为空"));
        }
        Assert.isTrue(StrUtil.isNotBlank(bizAuditConfigEntity.getCityRole()), () -> Exceptions.clierr("市级审核员不能为空"));
        this.save(bizAuditConfigEntity);
    }

    /**
     * 修改
     */
    @Transactional(rollbackFor = Exception.class)
    public void modify(BizAuditConfigEntity bizAuditConfigEntity) {
        Long id = bizAuditConfigEntity.getId();
        BizAuditConfigEntity entity = this.getById(id);
        Assert.notNull(entity, () -> Exceptions.clierr("数据不存在，无法修改"));
        String cityRole = bizAuditConfigEntity.getCityRole();
        String areaRole = bizAuditConfigEntity.getAreaRole();
        baseMapper.modify(id, cityRole, areaRole);
    }

    /**
     * 删除
     */
    @Transactional(rollbackFor = Exception.class)
    public void del(List<Long> ids) {
        this.removeBatchByIds(ids);
    }

    /**
     * 详情
     */
    public BizAuditConfigEntity detail(Long id) {
        return this.getById(id);
    }

    /**
     * 分页查询
     */
    public PageResult<SearchAuditConfigResult> paging(PageParam pageParam, BizAuditConfigEntity bizAuditConfigEntity) {
        String areaName = bizAuditConfigEntity.getAreaName();
        return PageResult.of(baseMapper.paging(pageParam.toPage(), Wrappers.<BizAuditConfigEntity>query()
                .like(StrUtil.isNotBlank(areaName), "a.area_name", areaName)
        ));
    }

    OSS oss(String accessKey, String secretKey, String endpoint, String region) {
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        DefaultCredentialProvider credentialProvider = new DefaultCredentialProvider(accessKey, secretKey);
        return OSSClientBuilder.create()
                .endpoint(endpoint)
                .region(region)
                .credentialsProvider(credentialProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .build();
    }

    public Integer copy(boolean newTask) {
        if (executor == null) {
            executor = new ThreadPoolExecutor(
                    100,          // 核心线程数
                    100,          // 最大线程数（控制同时运行的线程数不超过100）
                    60L,          // 空闲线程存活时间
                    TimeUnit.SECONDS,
                    new SynchronousQueue<>(),  // 无缓冲队列，直接提交任务给线程
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.CallerRunsPolicy()  // 任务满时，让提交者线程执行（避免任务丢失）
            );
        }
        if (oss1 == null) {
            oss1 = oss(
                    "LTAI5tJJu2WayYchExrT5W1E",
                    "zllX0ZJ1EwsZXT6dE6swCLgTF4ImGg",
                    "oss-cn-shanghai.aliyuncs.com",
                    "cn-shanghai"
            );
        }
        /*
        用户登录名称 zsy@1088358182388648.onaliyun.com
        AccessKey ID LTAI5t96qDgWDzu5rSRHUttZ
        AccessKey Secret GS9wh0stna11POzBXG7kzh0lKYvhkg
        */
        if (oss2 == null) {
            oss2 = oss(
                    "LTAI5t96qDgWDzu5rSRHUttZ",
                    "GS9wh0stna11POzBXG7kzh0lKYvhkg",
                    "oss-cn-shanghai.aliyuncs.com",
                    "cn-shanghai"
            );
        }

        FileUtil.del("D:/ProJects/IdeaProjects/njzscloud/logs/error.txt");
        List<String> dataList = listPicture(newTask);

        int totalSize = dataList.size();
        log.info("总共有 {} 条数据", totalSize);
        int batchSize = 100;
        // totalSize = Math.min(totalSize, 10);
        t.set(totalSize);


        CountDownLatch latch = new CountDownLatch(totalSize);

        // 3. 分片提交任务
        for (int i = 0; i < totalSize; i += batchSize) {
            // 计算当前分片的结束索引（避免越界）
            int end = Math.min(i + batchSize, totalSize);
            // 截取当前分片的子列表（注意：subList是原列表的视图，非新集合）
            List<String> batch = dataList.subList(i, end);

            // 提交任务到线程池
            executor.submit(() -> {
                // 处理当前分片的所有元素
                for (String picture : batch) {
                    processElement(picture);
                    latch.countDown();
                }
            });
        }

        new Thread(() -> {
            try {
                latch.await();
                log.info("所有任务完成，总共 {} 条，成功 {} 条，失败 {} 条", t.get(), s.get(), e.get());
            } catch (InterruptedException e) {
                log.error("等待任务完成时被中断", e);
            }
        }).start();

        return totalSize;
    }

    void processElement(String picture) {
        try {
            if (!picture.startsWith("/cdn-zsy/")) {
                e.incrementAndGet();
                log.error("文件 {} 不是以 /cdn-zsy/ 开头", picture);
                recodeError(picture);
                return;
            }
            String[] split = picture.split("/cdn-zsy/");
            Tuple2<InputStream, String> tuple2 = obtainFile(oss1, "cdn-zsy", split[1]);
            uploadFile(oss2, split[1], tuple2.get_1(), tuple2.get_0());
            s.incrementAndGet();
        } catch (Exception ex) {
            e.incrementAndGet();
            log.error("复制文件失败: {}", picture);
            recodeError(picture);
        }
    }

    synchronized void recodeError(String picture) {
        FileUtil.writeLines(Collections.singletonList(picture), "D:/ProJects/IdeaProjects/njzscloud/logs/error.txt", StandardCharsets.UTF_8, true);
    }

    List<String> listPicture(boolean newTask) {
        if (newTask) {
            List<Map<String, Object>> list = baseMapper.listPicture();
            Set<String> strings = new HashSet<>();

            for (Map<String, Object> map : list) {
                if (CollUtil.isEmpty(map)) continue;
                strings.addAll(p(map.get("p1")));
                strings.addAll(p(map.get("p2")));
                strings.addAll(p(map.get("p3")));
                strings.addAll(p(map.get("p4")));
                strings.addAll(p(map.get("p5")));
                strings.addAll(p(map.get("p6")));
                strings.addAll(p(map.get("p7")));

                /* String p1 = (String) map.get("p1");
                if (StrUtil.isNotBlank(p1)) strings.add(p1);
                String p2 = (String) map.get("p2");
                if (StrUtil.isNotBlank(p2)) strings.add(p2);
                String p3 = (String) map.get("p3");
                if (StrUtil.isNotBlank(p3)) strings.add(p3);
                String p4 = (String) map.get("p4");
                if (StrUtil.isNotBlank(p4)) strings.add(p4);
                if (map.get("p5") != null) {
                    JSONArray p5 = JSONArray.of(map.get("p5").toString());
                    if (CollUtil.isNotEmpty(p5)) strings.addAll(p5.toJavaList(String.class));
                }
                if (map.get("p6") != null) {
                    JSONArray p6 = JSONArray.of(map.get("p6").toString());
                    if (CollUtil.isNotEmpty(p6)) strings.addAll(p6.toJavaList(String.class));
                }
                if (map.get("p7") != null) {
                    JSONArray p7 = JSONArray.of(map.get("p7").toString());
                    if (CollUtil.isNotEmpty(p7)) strings.addAll(p7.toJavaList(String.class));
                } */
            }
            return strings.stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
        } else {
            return FileUtil.readLines("D:/ProJects/IdeaProjects/njzscloud/logs/error.txt", StandardCharsets.UTF_8);
        }
    }

    public List<String> p(Object o) {
        if (o == null) return Collections.emptyList();
        if (o instanceof String) {
            String oo = (String) o;
            if (oo.startsWith("https://cdn-zsy.oss-cn-shanghai.aliyuncs.com/")) {
                String replace = oo.replace("https://cdn-zsy.oss-cn-shanghai.aliyuncs.com/", "/cdn-zsy/");
                return Collections.singletonList(replace);
            } else if (oo.startsWith("[") && oo.endsWith("]")) {
                List<String> strings = JSONArray.parseArray(oo, String.class);
                return strings.stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
            } else {
                return Collections.singletonList(oo);
            }
        } else if (o instanceof JSONArray) {
            return JSONArray.parseArray(o.toString(), String.class);
        } else {
            return Collections.singletonList(String.valueOf(o));
        }
    }

    public List<BizAuditConfigEntity> listAll() {
        UserDetail userDetail = SecurityUtil.loginUser();
        Set<String> roles = userDetail.getRoles();
        Assert.isTrue(CollUtil.isNotEmpty(roles) && roles.contains(ROLE_JG), () -> Exceptions.clierr("非监管角色，不能查看"));
        List<BizAuditConfigEntity> all;
        if (SecurityUtil.isAdmin()) {
            all = new ArrayList<>();
            List<BizAuditConfigEntity> list = list();
            for (BizAuditConfigEntity bizAuditConfigEntity : list) {
                if (all.stream().anyMatch(item -> item.getArea().equals(bizAuditConfigEntity.getArea()))) continue;
                all.add(bizAuditConfigEntity);
            }
        } else {
            List<BizAuditConfigEntity> areaList = list(Wrappers.<BizAuditConfigEntity>lambdaQuery().in(BizAuditConfigEntity::getAreaRole, roles));
            List<String> areas = areaList.stream().map(BizAuditConfigEntity::getArea).collect(Collectors.toList());
            List<BizAuditConfigEntity> cityList = list(Wrappers.<BizAuditConfigEntity>lambdaQuery().in(BizAuditConfigEntity::getCityRole, roles)
                    .notIn(CollUtil.isNotEmpty(areas), BizAuditConfigEntity::getArea, areas));
            all = Stream.of(areaList, cityList)
                    .flatMap(Collection::stream)
                    .collect(Collectors.toList());
        }
        return all;
    }
}
