package com.fdkankan.pay.paypal.sdk;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fdkankan.pay.paypal.PayPalDefaultConfig;
import com.paypal.api.payments.*;
import com.paypal.base.codec.binary.Base64;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

@Service
public class PaypalService {
    private static Logger log = LoggerFactory.getLogger("programLog");

    @Autowired
    private APIContext apiContext;
    @Autowired
    private PayPalDefaultConfig config;

    private static final String CURRENCY = "USD";

    /**
     * 创建支付
     *
     * @param paymentEx
     * @return
     * @throws PayPalRESTException
     */
    @Transactional(rollbackFor = Exception.class)
    public Payment createPayment(PayPalmentEx paymentEx, String successUrl, String cancelUrl) throws PayPalRESTException {
        if (StringUtils.isEmpty(successUrl) || StringUtils.isEmpty(cancelUrl)) {
            throw new PayPalRESTException("缺少url");
        }
        Transaction transaction = new Transaction();
        transaction.setDescription(paymentEx.getDescription());
        // 将我们的订单ID保存到支付信息中，用于后面支付回传
        if (null != paymentEx.getOrderSn()) {
            transaction.setCustom(paymentEx.getOrderSn());
        }
        //订单价格
        Amount amount = new Amount();
        amount.setCurrency(CURRENCY);
        // 支付的总价，paypal会校验 total = subTotal + tax + ...
        amount.setTotal(paymentEx.getOrderTotal().toString());
        // 设置各种费用
        Details details = new Details();
        // 商品总价
        if (paymentEx.getSubTotal() != null) {
            details.setSubtotal(paymentEx.getSubTotal().toString());
        }
        // 税费
        if (paymentEx.getTax() != null) {
            details.setTax(paymentEx.getTax().toString());
        }

        amount.setDetails(details);

        transaction.setAmount(amount);

        ItemList itemList = new ItemList();
        // 收货地址
        PaypalOrderAddressEx orderAddress = paymentEx.getPaypayOrderAddressEx();
        if (orderAddress != null) {
            ShippingAddress shippingAddress = new ShippingAddress();
            if (StringUtils.isNotEmpty(orderAddress.getFirstName()) && StringUtils.isNotEmpty(orderAddress.getLastName())) {
                shippingAddress.setRecipientName(orderAddress.getFirstName() + "." + orderAddress.getLastName());
            }
            shippingAddress.setCountryCode(orderAddress.getCountryCode());
            shippingAddress.setState(orderAddress.getState());
            shippingAddress.setCity(orderAddress.getCity());
            shippingAddress.setLine1(orderAddress.getAddress());
            shippingAddress.setPhone(orderAddress.getPhone());
            shippingAddress.setPostalCode(orderAddress.getPostalCode());

            itemList.setShippingAddress(shippingAddress);
            itemList.setShippingPhoneNumber(orderAddress.getPhone());
        }

        // 商品明细
        List<PaypalOrderItemEx> orderItemList = paymentEx.getPaypalOrderItemExList();
        if (orderItemList != null && orderItemList.size() > 0) {
            List<Item> items = new ArrayList<>();
            for (PaypalOrderItemEx orderItemEx : orderItemList) {
                Item item = new Item();
                item.setSku(orderItemEx.getSku());
                item.setName(orderItemEx.getName());
                item.setPrice(orderItemEx.getPrice().toString());
                item.setQuantity(String.valueOf(orderItemEx.getQuantity()));
                item.setCurrency(CURRENCY);
                items.add(item);
            }
            itemList.setItems(items);
            transaction.setItemList(itemList);
        }

        List<Transaction> transactions = new ArrayList<>();
        transactions.add(transaction);

        // 支付信息
        Payer payer = new Payer();
        payer.setPaymentMethod(PaypalPaymentMethod.paypal.toString());

        Payment payment = new Payment();
        //刷新accessToken时间;
        apiContext = new APIContext("Bearer " + getAccessToken());
        apiContext.setConfigurationMap(config.paypalSdkConfig());

        payment.setIntent(PaypalPaymentIntent.sale.toString());
        payment.setPayer(payer);
        payment.setTransactions(transactions);

        //回调地址
        RedirectUrls redirectUrls = new RedirectUrls();
        redirectUrls.setReturnUrl(successUrl);
        redirectUrls.setCancelUrl(cancelUrl);
        payment.setRedirectUrls(redirectUrls);

        return payment.create(apiContext);
    }

    /**
     * 执行支付
     *
     * @param paymentId
     * @param payerId
     * @return
     * @throws PayPalRESTException
     */
    public Payment executePayment(String paymentId, String payerId) throws PayPalRESTException {
        Payment payment = new Payment();
        payment.setId(paymentId);
        PaymentExecution paymentExecute = new PaymentExecution();
        paymentExecute.setPayerId(payerId);
        apiContext = new APIContext("Bearer " + getAccessToken());
        apiContext.setConfigurationMap(config.paypalSdkConfig());
        return payment.execute(apiContext, paymentExecute);
    }

    /**
      * 获取token
      * 了解更多：https://developer.paypal.com/webapps/developer/docs/integration/mobile/verify-mobile-payment/
      * @return
      */
    private String getAccessToken() {
        BufferedReader reader = null;
        try {
            URL url = new URL(UrlUtils.TOKEN_URL);
            String authorization = config.getClientId() + ":" + config.getSecret();
            authorization = Base64.encodeBase64String(authorization.getBytes());

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");// 提交模式
            //设置请求头header
            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("Accept-Language", "en_US");
            conn.setRequestProperty("Authorization", "Basic " + authorization);
            // conn.setConnectTimeout(10000);//连接超时 单位毫秒
            // conn.setReadTimeout(2000);//读取超时 单位毫秒
            conn.setDoOutput(true);// 是否输入参数
            String params = "grant_type=client_credentials";
            conn.getOutputStream().write(params.getBytes());// 输入参数

            InputStreamReader inStream = new InputStreamReader(conn.getInputStream());
            reader = new BufferedReader(inStream);
            StringBuilder result = new StringBuilder();
            String lineTxt = null;
            while ((lineTxt = reader.readLine()) != null) {
                result.append(lineTxt);
            }
            reader.close();
            String accessTokey = JSONObject.parseObject(result.toString()).getString("access_token");
            log.info("getAccessToken:" + accessTokey);
            return accessTokey;
        } catch (Exception err) {
            err.printStackTrace();
        } finally {
            if (reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public String getPaymentDetails(String paymentId) {
        BufferedReader reader = null;
        try {
            URL url = new URL(UrlUtils.PAYMENT_DETAIL + paymentId);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");// 提交模式
            //设置请求头header
            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("Authorization", "Bearer " + getAccessToken());
            // conn.setConnectTimeout(10000);//连接超时 单位毫秒
            // conn.setReadTimeout(2000);//读取超时 单位毫秒
            InputStreamReader inStream = new InputStreamReader(conn.getInputStream());
            reader = new BufferedReader(inStream);
            StringBuilder result = new StringBuilder();
            String lineTxt = null;
            while ((lineTxt = reader.readLine()) != null) {
                result.append(lineTxt);
            }
            reader.close();
            return result.toString();
        } catch (Exception err) {
            err.printStackTrace();
        }finally {
            if (reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public boolean verifyPayment(String paymentId){
        //从PayPal获取付款详情
        String str = getPaymentDetails(paymentId);
        JSONObject detail = JSONObject.parseObject(str);
        //校验订单是否完成
        if("approved".equals(detail.getString("state"))){
            JSONObject transactions = detail.getJSONArray("transactions").getJSONObject(0);
            JSONObject amount = transactions.getJSONObject("amount");
            JSONArray relatedResources = transactions.getJSONArray("related_resources");
            //从数据库查询总金额与Paypal校验支付总金额
            double total = 0;
            if( total != amount.getDouble("total") ){
                return false;
            }
            //校验交易货币类型
            String currency = "USD";
            if( !currency.equals(amount.getString("currency")) ){
                return false;
            }
            //校验每个子订单是否完成
            for (int i = 0,j = relatedResources.size(); i < j; i++) {
                JSONObject sale = relatedResources.getJSONObject(i).getJSONObject("sale");
                if( !"completed".equals(sale.getString("state")) ){
                    System.out.println("子订单未完成,订单状态:"+sale.getString("state"));
                }
            }
            return true;
        }
        return false;
    }


}