package com.cftech.order.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cftech.core.util.SystemConfig;
import com.cftech.order.model.Order;
import com.cftech.product.model.Product;
import com.cftech.product.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import nuonuo.open.sdk.NNOpenSDK;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.UUID;

/**
 * 开票工具类
 * @author 13154
 */
@Component
@Slf4j
public class InvoiceUtil {

    @Autowired
    private ProductService productService;

    /**
     * 开票接口
     * @param orderObj
     * @param clerk 开票员
     * @param email 邮箱
     * @param type 0:
     * @param from  0:移动端 1：后台
     * @return
     */
    public String startInvoice (Order orderObj,String clerk,String email,String type,String from){


        NNOpenSDK sdk = NNOpenSDK.getIntance();
        // 授权企业税号
        String taxNum = SystemConfig.p.getProperty("INVOICE_TAX");
        String appKey = SystemConfig.p.getProperty("APP_KEY");
        String appSecret = SystemConfig.p.getProperty("APP_SECRET");
        // API方法名
        String method = SystemConfig.p.getProperty("INVOICE_API");
        // 访问令牌
        String token = SystemConfig.p.getProperty("INVOICE_TOKEN");
        // SDK请求地址
        String url = SystemConfig.p.getProperty("INVOICE_URL");
        // 唯一标识，32位随机码，无需修改，保持默认即可
        String senId = UUID.randomUUID().toString().replace("-", "");

        JSONObject order = new JSONObject();
        order.put("terminalNumber","");
        //购方电话  非必传
        order.put("buyerTel",orderObj.getMemberPhone());
        //清单标志：非清单:0；清单:1，默认:0  非必传
        order.put("listFlag","0");
        //推送方式：-1,不推送;0,邮箱;1,手机（默认）;2,邮箱、手机   非必填
        order.put("pushMode","0");
        //部门门店id（诺诺系统中的id） 非必填
        order.put("departmentId","9F7E9439CA8B4C60A2FFF3EA3290B088");
        //开票员id（诺诺系统中的id） 非必填
        order.put("clerkId","");
        //备注 非必填
        order.put("remark","");
        //复核人  非必填
        order.put("checker",SystemConfig.p.getProperty("CHECKER"));
        //收款人  非必填
        order.put("payee",SystemConfig.p.getProperty("PAYEE"));
        //购方地址  非必填
        order.put("buyerAddress",orderObj.getAddress());
        //购方税号（企业要填，个人可为空）
        order.put("buyerTaxNum","");
        //开票类型：1:蓝票;2:红票  必填
        order.put("invoiceType","1");
        //发票种类：p,普通发票(电票)(默认);c,普通发票(纸票);s,专用发票;e,收购发票(电票);f,收购发票(纸质);r,普通发票(卷式)  非必填
        order.put("invoiceLine","p");
        //推送邮箱（pushMode为0或2时，此项为必填） 必填
        order.put("email",email);
        //销方银行账号和开户行地址 非必填
        order.put("salerAccount",SystemConfig.p.getProperty("KAIHUHANG_ADDRESS"));
        //销方电话  必填
        order.put("salerTel",SystemConfig.p.getProperty("SALER_TEL"));
        //订单号 （每个企业唯一） 必填
        order.put("orderNo","OD19980115"); //todo
        // 开票完成回传发票信息地址  非必填
        order.put("callBackUrl","http:127.0.0.1/invoice/callback/");
        // 购方名称  必填
        if(type.equals("0")){
            order.put("buyerName","个人");
        }else{
            order.put("buyerName","企业名称");
        }
        // 订单时间  必填
        order.put("invoiceDate",orderObj.getCreateTimeStr());
        //冲红时填写的对应蓝票发票代码（红票必填，不满12位请左补0） 非必填
        order.put("invoiceCode","125999915630");
        //冲红时填写的对应蓝票发票号码（红票必填，不满8位请左补0） 非必填
        order.put("invoiceNum","00130865");
        //销方地址  必填
        order.put("salerAddress",SystemConfig.p.getProperty("SALER_ADDRESS"));
        //开票员  必填
        if(from.equals("1")){
            order.put("clerk",SystemConfig.p.getProperty("CLERK"));
        }else{
            order.put("clerk",clerk);
        }

        //购方手机（pushMode为1或2时，此项为必填） 必填
        order.put("buyerPhone","18516234460"); //todo
        //购方银行账号及开户行地址  非必填
        order.put("buyerAccount","");
        //成品油标志：非成品油(默认):0;成品油:1  非必填
        order.put("productOilFlag","0");
        //分机号（只能为空或者数字） 非必填
        order.put("extensionNumber","");
        //销方税号（使用沙箱环境请求时消息体参数salerTaxNum和消息头参数userTax填写339901999999142） 必填
        order.put("salerTaxNum",SystemConfig.p.getProperty("INVOICE_TAX"));
        //清单项目名称：对应发票票面项目名称（listFlag为1时，必填，默认为“详见销货清单”） 非必填
        order.put("listName","详见销货清单");
        //代开标志：0非代开;1代开。代开蓝票时备注要求填写文案：代开企业税号:***,代开企业名称:***；代开红票时备注要求填写文案：对应正数发票代码:***号码:***代开企业税号:***代开企业名称:*** 非必填
        order.put("proxyInvoiceFlag","0");


        /* --------------------------------------------------商品详情-----------------------------------------------------**/
        JSONObject detail = null;
        JSONArray detailArray = new JSONArray();
        JSONArray decArray = JSON.parseArray(orderObj.getDescription());
        //税率
        BigDecimal taxRate = new BigDecimal("0.13");
        //商品含税单价
        BigDecimal price = null;
        //商品数量
        BigDecimal num = null;
        //不含税金额  不含税金额 = （商品含税单价*商品数量）/ (1+0.13)
        BigDecimal taxExcludedAmount = null;
        //税额 税额 = 不含税金额*税率
        BigDecimal tax = null;
        //含税金额  含税金额 = 不含税金额+税额
        BigDecimal taxIncludedAmount = null;
        for (int i = 0; i<decArray.size(); i++){
            detail = new JSONObject();
            JSONObject jsonObject = decArray.getJSONObject(i);
            Product product = productService.fetchById(jsonObject.getString("productId"));
            price = new BigDecimal(jsonObject.getString("price"));
            num = new BigDecimal(jsonObject.getString("drugsNum"));
            taxExcludedAmount = (price.multiply(num)).divide(new BigDecimal(1).add(taxRate),2, RoundingMode.HALF_UP);
            tax = taxExcludedAmount.multiply(taxRate).setScale(2, BigDecimal.ROUND_HALF_UP);
            taxIncludedAmount = taxExcludedAmount.add(tax);

            //规格型号  非必填
            detail.put("specType",product.getFormat()); // todo
            // 不含税金额。红票为负。不含税金额、税额、含税金额任何一个不传时，会根据传入的单价，数量进行计算，可能和实际数值存在误差，建议都传入 非毕传
            detail.put("taxExcludedAmount",taxExcludedAmount.toString());
            // 发票行性质：0,正常行;1,折扣行;2,被折扣行  非必填
            detail.put("invoiceLineProperty","0");
            // 增值税特殊管理（优惠政策名称）,当favouredPolicyFlag为1时，此项必填
            detail.put("favouredPolicyName","0");
            //数量（开具红票时数量为负数） 非必填
            detail.put("num",num.toString()); //todo
            //单价含税标志：0:不含税,1:含税 必填
            detail.put("withTaxFlag","1");
            //税额，[不含税金额] * [税率] = [税额]；税额允许误差为 0.06。红票为负。不含税金额、税额、含税金额任何一个不传时，会根据传入的单价，数量进行计算，可能和实际数值存在误差，建议都传入 非必填
            //BigDecimal tax = new BigDecimal(orderObj.getPrice()).multiply(new BigDecimal(0.1));
            detail.put("tax",tax.toString());
            //优惠政策标识：0,不使用;1,使用  非必填
            detail.put("favouredPolicyFlag","0");
            //税率，注：纸票清单红票存在为null的情况  必填
            detail.put("taxRate","0.13");
            //单位 非必填
            detail.put("unit",product.getUnit()); //todo
            //扣除额，差额征收时填写，目前只支持填写一项。 注意：当传0、空或字段不传时，都表示非差额征税；传0.00才表示差额征税：0.00 非必填
            detail.put("deduction","0");
            //单价，当单价(price)为空时，数量(num)也必须为空；(price)为空时，含税金额(taxIncludedAmount)、不含税金额(taxExcludedAmount)、税额(tax)都不能为空
            detail.put("price",price.toString()); //todo
            //零税率标识 非必填
            detail.put("zeroRateFlag","0");
            //商品编码（商品税收分类编码开发者自行填写）非必填
            detail.put("goodsCode","1090511030000000000");
            //自行编码（可不填） 非必填
            detail.put("selfCode","130005426000000000");
            //商品名称（如invoiceLineProperty =1，则此商品行为折扣行，折扣行不允许多行折扣，折扣行必须紧邻被折扣行，商品名称必须与被折扣行一致） 必填
            detail.put("goodsName",product.getProductName()); //todo
            //含税金额，[不含税金额] + [税额] = [含税金额]，红票为负。不含税金额、税额、含税金额任何一个不传时，会根据传入的单价，数量进行计算，可能和实际数值存在误差，建议都传入 非必填
            //BigDecimal taxIncludedAmount = new BigDecimal(orderObj.getPrice()).add(tax);
            detail.put("taxIncludedAmount",taxIncludedAmount.toString());
            detailArray.add(detail);
        }

        order.put("invoiceDetail",detailArray);
        JSONObject total = new JSONObject();
        total.put("order",order);



        String result = sdk.sendPostSyncRequest(url, senId, appKey, appSecret, token, taxNum, method, total.toString());
        log.error(result);

        return result;
    }

}
