package com.crm.pay.service.impl.pay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.entity.callback.S2sPayCallbackEntity;
import com.crm.pay.entity.property.S2sPayPropertyEntity;
import com.crm.pay.service.CustomInfoService;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.S2sPayService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositAddEntity;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
import com.crm.rely.backend.model.pojo.table.CustomInfoTable;
import com.crm.rely.backend.model.pojo.table.FinanceDepositTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import com.crm.rely.backend.core.exception.PayValidatedException;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.util.*;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Connection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Slf4j
@Service
public class S2sPayServiceImpl extends BasePayServiceImpl implements S2sPayService {

    @Autowired
    private FinanceDepositService financeDepositService;
    @Autowired
    private CustomInfoService customInfoService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String pay(FinanceDepositAddEntity balanceSaveEntity) throws Exception {
        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.S2S_PAY_KEY);
        //通道配置实体
        S2sPayPropertyEntity payProperty = getPayProperty(channel, S2sPayPropertyEntity.class);

        balanceSaveEntity.setCurrency(channel.getCurrency());
        balanceSaveEntity.setTransformCurrency(channel.getTransformCurrency());

        FinanceDepositTable balanceTable = financeDepositService.save(balanceSaveEntity, channel);

        String url = getUrl(payProperty, balanceTable, balanceSaveEntity);
        
        return url;

    }

    /**
     * 回调处理数据
     *
     * @param callbackEntity
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String callback(S2sPayCallbackEntity callbackEntity) throws Exception {
        log.info(String.format("callback data:%s", JSON.toJSONString(callbackEntity)));

        if (Strings.isNullOrEmpty(callbackEntity.getHash())) {
            return Constants.FAIL;
        }
        //获取配置
        /*S2sPayPropertyEntity payProperty = getPayProperty(PayConstants.S2S_PAY_KEY, S2sPayPropertyEntity.class);

        boolean validate = validate(callbackEntity, payProperty.getPassword());
        if (!validate) {
            return Constants.FAIL;
        }*/

        //验证传输数据
        int status = PayConstants.CALLBACE_PROCESSING_STATUS;
        if ("success".equals(callbackEntity.getStatus()) && "settled".equals(callbackEntity.getOrder_status())) {
            status = PayConstants.CALLBACE_SUCCESS_STATUS;
        } else if ("fail".equals(callbackEntity.getStatus()) || "decline".equals(callbackEntity.getOrder_status())
                || "refund".equals(callbackEntity.getOrder_status())|| "reversal".equals(callbackEntity.getOrder_status())|| "chargeback".equals(callbackEntity.getOrder_status())) {
            status = PayConstants.CALLBACE_FAIL_STATUS;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(callbackEntity.getOrder_number(), callbackEntity.getId(),
                        status, callbackEntity);
        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(callbackEntity.getOrder_amount()));
        /**
         * 更新数据
         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);
        return Constants.SUCCESS;
    }

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(S2sPayPropertyEntity propertyEntity, FinanceDepositTable balanceTable,
                          FinanceDepositAddEntity balanceSaveEntity) throws Exception {
        CustomInfoTable customInfoTable = customInfoService.getById(balanceTable.getCustomId());

        Map<String, Object> map = getMap(propertyEntity,balanceTable,customInfoTable);

        Map<String, String> headers = new HashMap<>(1);
        headers.put("Content-Type", "application/json");

        Connection.Response response = HttpUtil.post(propertyEntity.getBaseUrl() + propertyEntity.getDepositUrl(), headers, JSON.toJSONString(map));
        log.info(String.format("url:%s,json:%s,body:%s", propertyEntity.getBaseUrl() + propertyEntity.getDepositUrl()
                , JSON.toJSONString(map), response.body()));

        JSONObject requestEntity = JSON.parseObject(response.body());
        if (requestEntity == null || Strings.isNullOrEmpty(requestEntity.getString("redirect_url"))) {
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        String url = requestEntity.getString("redirect_url");
        log.info(String.format("支付请求,请求orderNo:%s,请求url:%s", map.get("merchantOrderNo"), url));

        return url;
    }

    private Map<String, Object> getMap(S2sPayPropertyEntity propertyEntity, FinanceDepositTable balanceTable, CustomInfoTable customInfoTable) throws Exception {
        String orderNo = balanceTable.getSerial() + "_" + balanceTable.getLogin();

        JSONArray methodsJson = new JSONArray();
        methodsJson.add("card");

        JSONObject orderJson = new JSONObject();
        orderJson.put("number", orderNo);
        String amount = String.format("%.2f", balanceTable.getTransformAmount().doubleValue());
        orderJson.put("amount", amount);
        orderJson.put("currency", balanceTable.getTransformCurrency());
        orderJson.put("description", "cwg deposit");

        JSONObject customJson = new JSONObject();
        customJson.put("name", balanceTable.getName());
        customJson.put("email", customInfoTable.getEmail());

        JSONObject addressJson = new JSONObject();
        addressJson.put("country", customInfoTable.getCountry());
        if(!Strings.isNullOrEmpty(customInfoTable.getCity())){
            addressJson.put("city", customInfoTable.getCity());
        }
        //addressJson.put("state","CA");
        if(!Strings.isNullOrEmpty(customInfoTable.getState())){
            addressJson.put("district", customInfoTable.getState());
        }
        if(!Strings.isNullOrEmpty(customInfoTable.getAddressLine())){
            addressJson.put("address", customInfoTable.getAddressLine());
        }
        //addressJson.put("house_number", "17/2");
        if(!Strings.isNullOrEmpty(customInfoTable.getZipCode())){
            addressJson.put("zip", customInfoTable.getZipCode());
        }
        if(!Strings.isNullOrEmpty(customInfoTable.getPhone())){
            addressJson.put("phone", customInfoTable.getPhone());
        }

        JSONArray cardTokenJson = new JSONArray();
        cardTokenJson.add(UUIDUtil.getUUID());

        Map<String, Object> map = new LinkedHashMap<>();
        map.put("merchant_key", propertyEntity.getMerchantKey());
        map.put("operation", "purchase");
        map.put("methods", methodsJson);
        map.put("order", orderJson);
        map.put("success_url", propertyEntity.getSuccessUrl());

        map.put("customer", customJson);
        map.put("billing_address", addressJson);
        map.put("card_token", cardTokenJson);

        String md5 = MD5Util.getMD5((orderNo+amount+balanceTable.getTransformCurrency()+"cwg deposit"+propertyEntity.getPassword()).toUpperCase());
        String hash = ShaUtil.sha("SHA-1", md5);
        map.put("hash", hash);
        return map;
    }


    /**
     * 验证回调参数是否被篡改
     *
     * @param callDataEntity
     * @return
     * @throws ServiceException
     */
    private boolean validate(S2sPayCallbackEntity callDataEntity, String password) throws Exception {

        String _sign = callDataEntity.getHash();

        String md5 = MD5Util.getMD5((callDataEntity.getId()+callDataEntity.getOrder_number()+callDataEntity.getOrder_amount()+callDataEntity.getOrder_currency()+callDataEntity.getOrder_description()+password).toUpperCase());
        String hash = ShaUtil.sha("SHA-1", md5);

        log.info(String.format("order no:%scallback result sign compare--callback sign:%s, encryption sign result:%s"
                , callDataEntity.getOrder_number(), _sign, hash));
        return hash.equals(_sign);
    }

    public static void main(String[] args) throws Exception {
        String con = "{\n" +
                "    \"baseUrl\":\"https://pay.world-card.co\",\n" +
                "    \"depositUrl\":\"/api/v1/session\",\n" +
                "    \"notifyUrl\":\"https://ad.44a5c8109e4.com/s2spay/callback\",\n" +
                "    \"successUrl\":\"https://example.domain.com/success\",\n" +
                "    \"merchantKey\":\"ceabba1e-1879-11f1-8035-26c6ca4a03ae\",\n" +
                "    \"password\":\"726dd8e5be7bd6c525656b6c086c2915\",\n" +
                "}";
        System.out.println(AESUtil.encrypt(con, "bfa5559109f94c78af615bcf00d52060"));

        //String orderNo = balanceTable.getSerial() + "_" + balanceTable.getLogin();
        String orderNo = "2025032425767";
        JSONArray methodsJson = new JSONArray();
        methodsJson.add("card");
        JSONObject orderJson = new JSONObject();
        orderJson.put("number", orderNo);
        String amount = "100.00";
        orderJson.put("amount", amount);
        orderJson.put("currency", "USD");
        orderJson.put("description", "cwg");

        JSONObject customJson = new JSONObject();
        customJson.put("name", "John Doe");
        customJson.put("email", "test@gmail.com");

        JSONObject addressJson = new JSONObject();
        addressJson.put("country", "US");
        addressJson.put("city", "Los Angeles");
        addressJson.put("district", "Beverlywood");
        addressJson.put("address", "Moor Building 35274");
        addressJson.put("zip", "1563456");
        addressJson.put("phone", "347771112233");

        JSONArray cardTokenJson = new JSONArray();
        cardTokenJson.add(UUIDUtil.getUUID());

        Map<String, Object> map = new LinkedHashMap<>();
        map.put("merchant_key", "ceabba1e-1879-11f1-8035-26c6ca4a03ae");
        map.put("operation", "purchase");
        map.put("methods", methodsJson);
        map.put("order", orderJson);
        map.put("success_url", "https://example.domain.com/success");

        map.put("customer", customJson);
        map.put("billing_address", addressJson);
        //map.put("card_token", cardTokenJson);
        //map.put("req_token", true);
        //map.put("recurring_init", true);
        //map.put("schedule_id", UUID.randomUUID().toString());

        String md5 = MD5Util.getMD5((orderNo+amount+"USD"+"cwg"+"726dd8e5be7bd6c525656b6c086c2915").toUpperCase());
        String hash = ShaUtil.sha("SHA-1", md5);
        map.put("hash", hash);
;
        Map<String, String> headers = new HashMap<>(1);
        headers.put("Content-Type", "application/json");

        System.out.println(JSON.toJSONString(map));
        Connection.Response response = HttpUtil.post("https://pay.world-card.co/api/v1/session",headers,JSON.toJSONString(map));

        System.out.println(response.body());

        /*Map<String, Object> qmap = new LinkedHashMap<>();
        qmap.put("merchant_key", "ceabba1e-1879-11f1-8035-26c6ca4a03ae");
        qmap.put("order_id", "2025032425767");

        String md5 = MD5Util.getMD5(("2025032425767"+"726dd8e5be7bd6c525656b6c086c2915").toUpperCase());
        String hash = ShaUtil.sha("SHA-1", md5);
        System.out.println(hash);
        qmap.put("hash", hash);

        Map<String, String> headers = new HashMap<>(1);
        headers.put("Content-Type", "application/json");

        System.out.println(JSON.toJSONString(qmap));
        Connection.Response response = HttpUtil.post("https://pay.world-card.co/api/v1/payment/status",headers,JSON.toJSONString(qmap));

        System.out.println(response.body());*/


    }

}




