package com.storlead.sales.controller.material;

import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.sts20150401.models.AssumeRoleResponse;
import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
import com.aliyun.tea.TeaException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.storlead.framework.common.constant.CommonConstant;
import com.storlead.framework.common.result.Result;
import com.storlead.sales.pojo.entity.customer.SysResourceEntity;
import com.storlead.sales.service.customer.SysResourceService;
import com.storlead.sales.pojo.dto.material.MaterialEntryDTO;
import com.storlead.sales.pojo.entity.material.MaterialEntryRecordEntity;
import com.storlead.sales.pojo.vo.material.MaterialEntryVO;
import com.storlead.sales.service.material.MaterialEntryRecordService;
import com.storlead.system.pojo.entity.SystemOssConfigEntity;
import com.storlead.system.service.SystemOssConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.apache.commons.codec.binary.Base64;
import javax.annotation.Resource;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: sp-sales-platform
 * @description:
 * @author: chenkq
 * @create: 2025-05-16 15:31
 */
@Log4j2
@RestController
@RequestMapping("/material")
@Api(tags="销售: 物料进出记录")
public class MaterialEntryRecordApiController {

    @Resource
    private SystemOssConfigService ossConfigService;

    //OSS基础信息 替换为实际的 bucket 名称、 region-id、host。
    String bucket = "sp-sales-test";
    String region = "cn-shenzhen";
    String host = "http://oss-cn-shenzhen.aliyuncs.com";
    // 设置上传回调URL（即回调服务器地址），必须为公网地址。用于处理应用服务器与OSS之间的通信，OSS会在文件上传完成后，把文件上传信息通过此回调URL发送给应用服务器。
    //限定上传到OSS的文件前缀。
    String upload_dir = "";
    //指定过期时间，单位为秒。
    Long expire_time = 3600L;

    @Resource
    private MaterialEntryRecordService materialEntryRecordService;

    @Resource
    private SysResourceService sysResourceService;

    @ApiOperation("进出记录增加")
    @PostMapping("save")
    public Result save(@RequestBody MaterialEntryRecordEntity entity) {
        materialEntryRecordService.saveOrUpdate(entity);
        if (!CollectionUtils.isEmpty(entity.getResourceIdList())) {
            sysResourceService.updateResourceById(null,"1000",entity.getId(),entity.getResourceIdList());
        }
        return Result.ok();
    }

    @ApiOperation("分页查询")
    @PostMapping("listPage")
    public Result listPage(@RequestBody MaterialEntryDTO param) {
        IPage<MaterialEntryRecordEntity> page = new Page<>(param.getPageIndex(),param.getPageSize());
        LambdaQueryWrapper<MaterialEntryRecordEntity> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.isNotNull(MaterialEntryRecordEntity::getEntryTime);
        if (StrUtil.isNotBlank(param.getBeginCycleTime())) {
            String beginCycleTime = param.getBeginCycleTime() ;//+" 00:00:00";
            queryWrapper.ge(MaterialEntryRecordEntity::getEntryTime, beginCycleTime);
        }
        if (StrUtil.isNotBlank(param.getEndCycleTime())) {
            String endCycleTime = param.getEndCycleTime() ;//+" 23:59:59";
            queryWrapper.le(MaterialEntryRecordEntity::getEntryTime,endCycleTime);
        }
        if (StrUtil.isNotBlank(param.getInspectionType())) {
            queryWrapper.eq(MaterialEntryRecordEntity::getInspectionType,param.getInspectionType());
        }
        queryWrapper.eq(MaterialEntryRecordEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
        queryWrapper.orderByDesc(MaterialEntryRecordEntity::getCreateTime);
        IPage<MaterialEntryRecordEntity> pageList = materialEntryRecordService.page(page, queryWrapper);
        if (CollectionUtils.isEmpty(pageList.getRecords())) {
            return Result.result(pageList);
        }
        DefaultMapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        List<MaterialEntryVO> vos = mapperFactory.getMapperFacade().mapAsList(pageList.getRecords(),MaterialEntryVO.class);
        vos.forEach(e -> {
            e.setIsEdit(isCreatedBefore72Hours(e.getCreateTime()));
        });
        Map<Long, List<SysResourceEntity>> resMap = materialEntryRecordService.listResource(vos.stream().map(MaterialEntryRecordEntity::getId).collect(Collectors.toList()));
        if (!CollectionUtils.isEmpty(resMap)) {
            vos.forEach(e -> {
                List<SysResourceEntity> rls = resMap.get(e.getId());
                if (!CollectionUtils.isEmpty(rls)) {
                    e.setResourceList(rls);
                    e.setResourceIdList(rls.stream().map(SysResourceEntity::getId).collect(Collectors.toList()));
                }
            });
        }
        IPage<MaterialEntryVO> pageVO =new Page<>(param.getPageIndex(), param.getPageSize());
        pageVO.setTotal(page.getTotal());
        pageVO.setPages(page.getPages());
        pageVO.setRecords(vos);
        pageVO.setCurrent(page.getCurrent());
        return Result.result(pageVO);
    }

    @ApiOperation("按照日期查询")
    @PostMapping("listData")
    public Result listData(@RequestBody MaterialEntryDTO param) {

        LambdaQueryWrapper<MaterialEntryRecordEntity> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.isNotNull(MaterialEntryRecordEntity::getEntryTime);
        if (StrUtil.isNotBlank(param.getBeginCycleTime())) {
            String beginCycleTime = param.getBeginCycleTime() ;//+" 00:00:00";
            queryWrapper.ge(MaterialEntryRecordEntity::getEntryTime, beginCycleTime);
        }
        if (StrUtil.isNotBlank(param.getEndCycleTime())) {
            String endCycleTime = param.getEndCycleTime() ;//+" 23:59:59";
            queryWrapper.le(MaterialEntryRecordEntity::getEntryTime,endCycleTime);
        }
        if (StrUtil.isNotBlank(param.getInspectionType())) {
            queryWrapper.eq(MaterialEntryRecordEntity::getInspectionType,param.getInspectionType());
        }
        queryWrapper.eq(MaterialEntryRecordEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
        queryWrapper.orderByDesc(MaterialEntryRecordEntity::getEntryTime);
        List<MaterialEntryRecordEntity> materialls = materialEntryRecordService.list(queryWrapper);
        if (CollectionUtils.isEmpty(materialls)) {
            return Result.result(null);
        }
        materialls.forEach(e -> {
            e.setIsEdit(isCreatedBefore72Hours(e.getCreateTime()));
        });
        DefaultMapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        List<MaterialEntryVO> vos = mapperFactory.getMapperFacade().mapAsList(materialls,MaterialEntryVO.class);
        Map<Long, List<SysResourceEntity>> resMap = materialEntryRecordService.listResource(vos.stream().map(MaterialEntryRecordEntity::getId).collect(Collectors.toList()));
        if (!CollectionUtils.isEmpty(resMap)) {
            vos.forEach(e -> {
                List<SysResourceEntity> rls = resMap.get(e.getId());
                if (!CollectionUtils.isEmpty(rls)) {
                    e.setResourceList(rls);
                    e.setResourceIdList(rls.stream().map(SysResourceEntity::getId).collect(Collectors.toList()));
                }
            });
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
//        Map<String, List<MaterialEntryVO>> groupedByDate = vos.stream()
//                .collect(Collectors.groupingBy(task -> task.getEntryTime().format(formatter)));

        Map<String, List<MaterialEntryVO>> groupedByDate = vos.stream()
                .collect(Collectors.groupingBy(
                        task -> task.getEntryTime().format(formatter),
                        () -> new TreeMap<>(Collections.reverseOrder()),
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                list -> list.stream()
                                        .sorted(Comparator.comparing(MaterialEntryVO::getEntryTime).reversed())
                                        .collect(Collectors.toList())
                        )
                ));

        return Result.result(groupedByDate);
    }

    @GetMapping(value = "/get-by-id")
    @ApiOperation(value = "客户跟进记录查询-通过id查看详情", notes = "客户跟进记录查询-通过id查看详情")
    public Result<MaterialEntryVO> getById(@RequestParam(name="id",required=false) Long id) {

        MaterialEntryVO entryVO = materialEntryRecordService.getVOById(id);
        entryVO.setIsEdit(isCreatedBefore72Hours(entryVO.getCreateTime()));
        return Result.result(entryVO);
    }

//    @ApiOperation("查询")
//    @PostMapping("list")
//    public Result list(@RequestBody MaterialEntryDTO param) {
//
//        LambdaQueryWrapper<MaterialEntryRecordEntity> queryWrapper = new LambdaQueryWrapper();
//        queryWrapper.eq(MaterialEntryRecordEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
//
//        List<MaterialEntryRecordEntity> pageList = materialEntryRecordService.list(queryWrapper);
//        return Result.result(pageList);
//    }

    @ApiOperation("删除")
    @PostMapping("delete")
    public Result delete(Long id) {
        if(Objects.isNull(id)) {
            return Result.error("参数错误");
        }
        materialEntryRecordService.lgDelete(id);
        return Result.ok();
    }


    public Boolean isCreatedBefore72Hours(Date createTime) {
        if (createTime == null) {
            return false;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR_OF_DAY, -72); // 当前时间减去 72 小时
        Date threshold = calendar.getTime();
        Boolean b = createTime.before(threshold);
        if (b) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 通过指定有效的时长（秒）生成过期时间。
     * @param seconds 有效时长（秒）。
     * @return ISO8601 时间字符串，如："2014-12-01T12:00:00.000Z"。
     */
    public static String generateExpiration(long seconds) {
        // 获取当前时间戳（以秒为单位）
        long now = Instant.now().getEpochSecond();
        // 计算过期时间的时间戳
        long expirationTime = now + seconds;
        // 将时间戳转换为Instant对象，并格式化为ISO8601格式
        Instant instant = Instant.ofEpochSecond(expirationTime);
        // 定义时区为UTC
        ZoneId zone = ZoneOffset.UTC;
        // 将 Instant 转换为 ZonedDateTime
        ZonedDateTime zonedDateTime = instant.atZone(zone);
        // 定义日期时间格式，例如2023-12-03T13:00:00.000Z
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        // 格式化日期时间
        String formattedDate = zonedDateTime.format(formatter);
        // 输出结果
        return formattedDate;
    }
    //初始化STS Client
    public static com.aliyun.sts20150401.Client createStsClient() throws Exception {
        String OSS_ACCESS_KEY_ID = "LTAI5t5n6K9ramopnY4KNQnM";
        String OSS_ACCESS_KEY_SECRET = "xmA6wObeUAKDux92DX3qfLNWAQAQZm";
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config().setAccessKeyId(OSS_ACCESS_KEY_ID)
                // 必填，请确保代码运行环境设置了环境变量 OSS_ACCESS_KEY_SECRET。
                .setAccessKeySecret(OSS_ACCESS_KEY_SECRET);
        // Endpoint 请参考 https://api.aliyun.com/product/Sts
        // id : cn-shenzhen
        //服务地址： sts.cn-shenzhen.aliyuncs.com
        //vpc 地址 ： sts-vpc.cn-shenzhen.aliyuncs.com
        config.endpoint = "sts.cn-shenzhen.aliyuncs.com";
        return new com.aliyun.sts20150401.Client(config);
    }

    /**
     * 获取STS临时凭证
     * @return AssumeRoleResponseBodyCredentials 对象
     */
    public static AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials getCredential() throws Exception {
        String OSS_STS_ROLE_ARN = "acs:ram::1360195429377516:role/ramossstsrole";
        String yourRoleSessionName = "AliyunOSSTokenGeneratorRole";
        com.aliyun.sts20150401.Client client = MaterialEntryRecordApiController.createStsClient();
        com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest()
                // 必填，请确保代码运行环境设置了环境变量 OSS_STS_ROLE_ARN
                .setRoleArn(OSS_STS_ROLE_ARN)
                .setRoleSessionName(yourRoleSessionName);// 自定义会话名称
        com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
        try {
            // 复制代码运行请自行打印 API 的返回值
            AssumeRoleResponse response = client.assumeRoleWithOptions(assumeRoleRequest, runtime);
            // credentials里包含了后续要用到的AccessKeyId、AccessKeySecret和SecurityToken。
            return response.body.credentials;
        } catch (TeaException error) {
            // 此处仅做打印展示，请谨慎对待异常处理，在工程项目中切勿直接忽略异常。
            // 错误 message
            log.error("_error ",error);
        } catch (Exception _error) {
            TeaException error = new TeaException(_error.getMessage(), _error);
            // 此处仅做打印展示，请谨慎对待异常处理，在工程项目中切勿直接忽略异常。
            // 错误 message
            log.error("_error ",_error);
            // 诊断地址
//            System.out.println(error.getData().get("Recommend"));
        }
        // 返回一个默认的错误响应对象，避免返回null
        AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials defaultCredentials = new AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials();
        defaultCredentials.accessKeyId = "ERROR_ACCESS_KEY_ID";
        defaultCredentials.accessKeySecret = "ERROR_ACCESS_KEY_SECRET";
        defaultCredentials.securityToken = "ERROR_SECURITY_TOKEN";
        return defaultCredentials;
    }
    @GetMapping("/get_post_signature_for_oss_upload")
    public Result<Map<String, String>> getPostSignatureForOssUpload() throws Exception {
        AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials sts_data = getCredential();

        SystemOssConfigEntity  systemOssConfig = ossConfigService.getById(1);

        String accesskeyid =  sts_data.accessKeyId;
        String accesskeysecret =  sts_data.accessKeySecret;
        String securitytoken =  sts_data.securityToken;

        //获取x-oss-credential里的date，当前日期，格式为yyyyMMdd
        LocalDate today = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String date = today.format(formatter);

        //获取x-oss-date
        ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(ZoneOffset.UTC);
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
        String x_oss_date = now.format(formatter2);

        // 步骤1：创建policy。
        String x_oss_credential = accesskeyid + "/" + date + "/" + region + "/oss/aliyun_v4_request";

        ObjectMapper mapper = new ObjectMapper();

        Map<String, Object> policy = new HashMap<>();
        policy.put("expiration", generateExpiration(expire_time));

        List<Object> conditions = new ArrayList<>();

        Map<String, String> bucketCondition = new HashMap<>();
        bucketCondition.put("bucket", bucket);
        conditions.add(bucketCondition);

        Map<String, String> securityTokenCondition = new HashMap<>();
        securityTokenCondition.put("x-oss-security-token", securitytoken);
        conditions.add(securityTokenCondition);

        Map<String, String> signatureVersionCondition = new HashMap<>();
        signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
        conditions.add(signatureVersionCondition);

        Map<String, String> credentialCondition = new HashMap<>();
        credentialCondition.put("x-oss-credential", x_oss_credential); // 替换为实际的 access key id
        conditions.add(credentialCondition);

        Map<String, String> dateCondition = new HashMap<>();
        dateCondition.put("x-oss-date", x_oss_date);
        conditions.add(dateCondition);

        conditions.add(Arrays.asList("content-length-range", 1, 10240000));
        conditions.add(Arrays.asList("eq", "$success_action_status", "200"));
        conditions.add(Arrays.asList("starts-with", "$key", upload_dir));

        policy.put("conditions", conditions);

        String jsonPolicy = mapper.writeValueAsString(policy);

        // 步骤2：构造待签名字符串（StringToSign）。
        String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
        // System.out.println("stringToSign: " + stringToSign);

        // 步骤3：计算SigningKey。
        byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), date);
        byte[] dateRegionKey = hmacsha256(dateKey, region);
        byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
        byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
        // System.out.println("signingKey: " + BinaryUtil.toBase64String(signingKey));

        // 步骤4：计算Signature。
        byte[] result = hmacsha256(signingKey, stringToSign);
        String signature = BinaryUtil.toHex(result);
        // System.out.println("signature:" + signature);


        Map<String, String> response = new HashMap<>();
        // 将数据添加到 map 中
        response.put("version", "OSS4-HMAC-SHA256");
        response.put("policy", stringToSign);
        response.put("x_oss_credential", x_oss_credential);
        response.put("x_oss_date", x_oss_date);
        response.put("signature", signature);
        response.put("security_token", securitytoken);
        response.put("dir", upload_dir);
        response.put("host", host);
        // 返回带有状态码 200 (OK) 的 ResponseEntity，返回给Web端，进行PostObject操作
        return Result.result(response);
    }

    public static byte[] hmacsha256(byte[] key, String data) {
        try {
            // 初始化HMAC密钥规格，指定算法为HMAC-SHA256并使用提供的密钥。
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");

            // 获取Mac实例，并通过getInstance方法指定使用HMAC-SHA256算法。
            Mac mac = Mac.getInstance("HmacSHA256");
            // 使用密钥初始化Mac对象。
            mac.init(secretKeySpec);

            // 执行HMAC计算，通过doFinal方法接收需要计算的数据并返回计算结果的数组。
            byte[] hmacBytes = mac.doFinal(data.getBytes());

            return hmacBytes;
        } catch (Exception e) {
            throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
        }
    }
}
