/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the yifu4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.yifu.cloud.plus.v1.yifu.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yifu.cloud.plus.v1.yifu.admin.api.entity.SysDictItem;
import com.yifu.cloud.plus.v1.yifu.admin.api.entity.SysGuaziBankBranch;

import com.yifu.cloud.plus.v1.yifu.admin.config.GzConfig;
import com.yifu.cloud.plus.v1.yifu.admin.mapper.SysGuaziBankBranchMapper;
import com.yifu.cloud.plus.v1.yifu.admin.service.SysGuaziBankBranchService;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ClientNameConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 瓜子银行支行信息
 *
 * @author chenyx
 * @date 2025-06-17 09:43:32
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class SysGuaziBankBranchServiceImpl extends ServiceImpl<SysGuaziBankBranchMapper, SysGuaziBankBranch> implements SysGuaziBankBranchService {

	private static final String STRING = "abcdefghijklmnopqrstuvwxyz";
	private static final String APP_KEY = "appkey";
	private static final String EXPIRES = "expires";
	private static final String NONCE = "nonce";
	private static final String SIGNATURE = "signature";

	@Autowired
	private GzConfig gzConfig;

	private RestTemplate restTemplate = new RestTemplate();

	/**
	 * 瓜子银行支行信息简单分页查询
	 *
	 * @param sysGuaziBankBranch 瓜子银行支行信息
	 * @return IPage<SysGuaziBankBranch>
	 */
	@Override
	public IPage<SysGuaziBankBranch> getSysGuaziBankBranchPage(Page<SysGuaziBankBranch> page, SysGuaziBankBranch sysGuaziBankBranch) {
		return baseMapper.getSysGuaziBankBranchPage(page, sysGuaziBankBranch);
	}

	/**
	 * 拉取瓜子支行信息
	 *
	 * @param startTime
	 * @param endTime
	 * @return R
	 */
	@Override
	public R pushBankBranck(String startTime, String endTime, Integer pageNum) {
		Map<String, Object> params = new HashMap<>();
		params.put("pageNum", pageNum);
		params.put("pageSize", 10000);
		params.put("startTime", startTime);
		params.put("endTime", endTime);
		params.put("appsecret", gzConfig.getAppsecret());
		params.put("tid", gzConfig.getTid());

		addSignature(params, gzConfig.getAppkey(), gzConfig.getAppsecret());

		params.remove("startTime", startTime);
		params.remove("endTime", endTime);
		String sortedParams = getEncodeString(params);
		sortedParams += "&startTime=" + startTime + "&endTime=" + endTime;
		// 调取瓜子接口，拿到支行数据
		String result = gzConfig.getGzBankInfo(restTemplate, sortedParams);

		if (result != null && result.contains("code") && result.contains("data")) {
			JSONObject resultObject = JSON.parseObject(result);
			String code = resultObject.getString("code");
			if (Common.isNotNull(code) && "S00000".equals(code)) {
				JSONArray dataArray = (JSONArray) resultObject.get("data");
				if(dataArray.size() == 0){
					return R.ok("当天暂为拉取到新数据");
				}
				JSONObject dataObject;
				Integer cnapsId;

				// 获取已存在数据库的支行信息
				Set<Integer> checkCnapsIdSet = new HashSet<>();
				Set<Integer> haveCnapsIdSet = new HashSet<>();
				for (int i=0;i<dataArray.size(); i++) {
					dataObject = (JSONObject)dataArray.get(i);
					cnapsId = dataObject.getInteger("cnapsId");
					checkCnapsIdSet.add(cnapsId);
				}

				LambdaQueryWrapper<SysGuaziBankBranch> findQuery = Wrappers.<SysGuaziBankBranch>lambdaQuery()
						.in(SysGuaziBankBranch::getCnapsId, checkCnapsIdSet);
				List<SysGuaziBankBranch> findCnapsIdList = this.list(findQuery);
				if(Common.isNotNull(findCnapsIdList)){
					haveCnapsIdSet = findCnapsIdList.stream().map(SysGuaziBankBranch::getCnapsId).collect(Collectors.toSet());
				}

				String bankCd;
				String cnapsNum;
				String bankDescr;
				String stateId;
				String cityId;
				String effStatus;
				SysGuaziBankBranch saveOne;
				List<SysGuaziBankBranch> saveList = new ArrayList<>();
				// 开始处理支行数据
				for (int i=0;i<dataArray.size(); i++) {
					dataObject = (JSONObject)dataArray.get(i);
					bankCd = dataObject.getString("bankCd");
					cnapsId = dataObject.getInteger("cnapsId");
					cnapsNum = dataObject.getString("cnapsNum");
					bankDescr = dataObject.getString("bankDescr");
					stateId = dataObject.getString("stateId");
					cityId = dataObject.getString("cityId");
					effStatus = dataObject.getString("effStatus");

					// cnapsId 已存在就更新，否则新增
					if(Common.isNotNull(haveCnapsIdSet) && haveCnapsIdSet.contains(cnapsId)){
						LambdaUpdateWrapper<SysGuaziBankBranch> updateInfoWrapper = new LambdaUpdateWrapper<>();
						updateInfoWrapper.eq(SysGuaziBankBranch::getCnapsId, cnapsId)
								.set(SysGuaziBankBranch::getBankCd, bankCd)
								.set(SysGuaziBankBranch::getCnapsNum, cnapsNum)
								.set(SysGuaziBankBranch::getBankDescr, bankDescr)
								.set(SysGuaziBankBranch::getStateId, stateId)
								.set(SysGuaziBankBranch::getCityId, cityId)
								.set(SysGuaziBankBranch::getEffStatus, effStatus)
								.set(SysGuaziBankBranch::getUpdateBy, "1")
								.set(SysGuaziBankBranch::getUpdateTime, LocalDateTime.now());
						this.update(null, updateInfoWrapper);
					} else {
						saveOne = new SysGuaziBankBranch();
						saveOne.setBankCd(bankCd);
						saveOne.setCnapsId(cnapsId);
						saveOne.setCnapsNum(cnapsNum);
						saveOne.setBankDescr(bankDescr);
						saveOne.setCityId(cityId);
						saveOne.setStateId(stateId);
						saveOne.setEffStatus(effStatus);
						saveOne.setCreateBy("1");
						saveOne.setCreateName("系统");
						saveOne.setCreateTime(LocalDateTime.now());
						saveList.add(saveOne);
					}
				}

				if(Common.isNotNull(saveList)){
					this.saveBatch(saveList);
				}

				// 一页更新完，再调下一页
				this.pushBankBranck(startTime, endTime, pageNum+1);

				return R.ok();
			}
		}
		return R.failed("瓜子接口响应异常");
	}


	/**
	 * 生成签名并且将签名加到参数表中
	 *
	 * @param params    业务参数列表信息
	 * @param appKey
	 * @param appSecret
	 * @return
	 */
	private static Map<String, Object> addSignature(Map<String, Object> params, String appKey, String appSecret) {
		String sign = generateSignature(params, appKey, appSecret);
		params.put(SIGNATURE, sign);
		return params;
	}

	/**
	 * 根据参数计算签名值
	 *
	 * @param params
	 * @return
	 */
	private static String generateSignature(Map<String, Object> params, String appKey, String appSecret) {
		if (params == null ) {
			return null;
		}
		params.put(APP_KEY, appKey);
		params.put(EXPIRES, getCurrentSecond());
		params.put(NONCE, generateRandomStr(6));
		String sortedParams = getEncodeString(params);
		return generateSignature(sortedParams, appSecret);
	}

	/**
	 * 生成签名 取5-15共10位返回
	 *
	 * @param params
	 * @param appSecret
	 * @return
	 */
	private static String generateSignature(String params, String appSecret) {
		String result = md5(sha256HMACEncode(params, appSecret)).substring(5, 15);
		return result;
	}

	private static String md5(String value) {
		try {
			MessageDigest md = MessageDigest.getInstance("md5");
			byte[] e = md.digest(value.getBytes());
			return byteToHexString(e);
		} catch (NoSuchAlgorithmException e) {
		}
		return null;
	}

	private static String byteToHexString(byte[] salt) {
		StringBuffer hexString = new StringBuffer();
		for (int i = 0; i < salt.length; i++) {
			String hex = Integer.toHexString(salt[i] & 0xFF);
			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			hexString.append(hex.toLowerCase());
		}
		return hexString.toString();
	}

	/**
	 * sha256取hash Base64编码
	 *
	 * @param params
	 * @param secret
	 * @return
	 */
	private static String sha256HMACEncode(String params, String secret) {
		String result = "";
		try {
			Mac sha256HMAC = Mac.getInstance("HmacSHA256");
			SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
			sha256HMAC.init(secretKey);
			byte[] sha256HMACBytes = sha256HMAC.doFinal(params.getBytes());
			String hash = Base64.encodeBase64String(sha256HMACBytes);
			return hash;
		} catch (Exception e) {
		}
		return result;
	}

	// 获取当前时间秒数+60S
	private static String getCurrentSecond() {
		return (System.currentTimeMillis() / 1000 + 60) + "";
	}

	// 获取len个随机字符串
	private static String generateRandomStr(int len) {
		StringBuffer sb = new StringBuffer();
		int count = len <= STRING.length() ? len : STRING.length();
		Random random = new Random();
		for (int i = 0; i < count; i++) {
			sb.append(STRING.charAt(random.nextInt(STRING.length() - 1)));
		}
		return sb.toString();
	}

	// 通过参数集合map 组装成需要签名的字符串id=123&name=456
	public static String getEncodeString(Map<String, Object> params) {
		if (params == null || params.size() == 0) {
			return "";
		}
		Iterator<String> it = params.keySet().iterator();
		ArrayList<String> al = new ArrayList<String>();
		while (it.hasNext()) {
			al.add(it.next());
		}
		// 字母升序排列
		Collections.sort(al);
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < al.size(); i++) {
			try {
				String key = al.get(i);
				sb.append(URLEncoder.encode(key == null ? "" : key.toString(), "UTF-8"));
				sb.append("=");
				String item = null;
				Object value = params.get(key);
				item = URLEncoder.encode(value == null ? "" : value.toString(), "UTF-8");
				sb.append(item);
			} catch (UnsupportedEncodingException e) {
			} catch (NullPointerException e) {
			}
			sb.append("&");
		}
		String result = sb.toString();
		return result.substring(0, result.length() - 1);
	}



}
