package com.usoftchina.qywx.sdk;

import com.usoftchina.qywx.sdk.config.QywxProperties;
import com.usoftchina.qywx.sdk.dto.*;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.ModelMap;

import java.util.List;

/**
 * 电子发票
 * <p>
 * 报销发票接口及jsapi用于在应用中选择微信卡包中的电子发票实现电子化报销，该接口仅对认证的企业微信账号开放。具体操作步骤如下：
 * <ol>
 * <li>用户在应用中发票报销，选择电子发票类型；</li>
 * <li>应用调用JS-SDK“chooseInvoice接口”拉起微信卡包，展示发票列表</li>
 * <li>用户选择电子发票提交报销；</li>
 * <li>报销方调用API接口查询发票信息，核实后锁定电子发票</li>
 * <li>报销方打款给用户后，调用接口核销电子发票</li>
 * </ol>
 *
 * @author yingp
 */
public class InvoiceSdk extends BaseSdk {
    public InvoiceSdk(QywxProperties properties) {
        super(properties);
    }

    /**
     * 查询电子发票
     * 报销方在获得用户选择的电子发票标识参数后，可以通过该接口查询电子发票的结构化信息，并获取发票PDF文件。
     * 仅认证的企业微信账号有接口权限
     *
     * @param agentCode   应用code
     * @param cardId      发票id
     * @param encryptCode 加密code
     */
    public GetInvoiceInfoResp getInvoiceInfo(String agentCode, String cardId, String encryptCode) {
        ResponseEntity<GetInvoiceInfoResp> resp = restTemplate.postForEntity(
                baseUrl + "/cgi-bin/card/invoice/reimburse/getinvoiceinfo?access_token={access_token}",
                new ModelMap("card_id", cardId).addAttribute("encrypt_code", encryptCode),
                GetInvoiceInfoResp.class,
                new ModelMap("access_token", getAccessToken(agentCode)));
        assertOK(resp);
        return resp.getBody();
    }

    /**
     * 批量查询电子发票
     * 报销方在获得用户选择的电子发票标识参数后，可以通过该接口批量查询电子发票的结构化信息。
     *
     * @param agentCode   应用code
     * @param req
     * @return
     */
    public List<BatchGetInvoiceInfoResp.Invoice> batchGetInvoiceInfo(String agentCode, BatchGetInvoiceInfoReq req) {
        ResponseEntity<BatchGetInvoiceInfoResp> resp = restTemplate.postForEntity(
                baseUrl + "/cgi-bin/card/invoice/reimburse/getinvoiceinfo?access_token={access_token}",
                req.build(), BatchGetInvoiceInfoResp.class,
                new ModelMap("access_token", getAccessToken(agentCode)));
        assertOK(resp);
        return resp.getBody().getItem_list();
    }

    /**
     * 更新发票状态
     * <p>
     * 报销企业和报销服务商可以通过该接口对某一张发票进行锁定、解锁和报销操作。各操作的业务含义及在用户端的表现如下：
     * 锁定：电子发票进入了企业的报销流程时应该执行锁定操作，执行锁定操作后的电子发票仍然会存在于用户卡包内，但无法重复提交报销。
     * 解锁：当电子发票由于各种原因，无法完成报销流程时，应执行解锁操作。执行锁定操作后的电子发票将恢复可以被提交的状态。
     * 报销：当电子发票报销完成后，应该使用本接口执行报销操作。执行报销操作后的电子发票将从用户的卡包中移除，用户可以在卡包的消息中查看到电子发票的核销信息。注意，报销为不可逆操作，请开发者慎重调用
     * </p>
     *
     * @param agentCode   应用code
     * @param cardId      发票id
     * @param encryptCode 加密code
     * @param status      发票状态
     */
    public void updateInvoiceStatus(String agentCode, String cardId, String encryptCode, InvoiceStatus status) {
        ResponseEntity<BaseResp> resp = restTemplate.postForEntity(
                baseUrl + "/cgi-bin/card/invoice/reimburse/updateinvoicestatus?access_token={access_token}",
                new ModelMap("card_id", cardId)
                        .addAttribute("encrypt_code", encryptCode)
                        .addAttribute("reimburse_status", status.name()),
                BaseResp.class,
                new ModelMap("access_token", getAccessToken(agentCode)));
        assertOK(resp);
    }

    /**
     * 批量更新发票状态
     * <p>
     * 发票平台可以通过该接口对某个成员的一批发票进行锁定、解锁和报销操作。注意，报销状态为不可逆状态，请开发者慎重调用。
     * 报销方须保证在报销、锁定、解锁后及时将状态同步至微信侧，保证用户发票可以正常使用
     * 批量更新发票状态接口为事务性操作，如果其中一张发票更新失败，列表中的其它发票状态更新也会无法执行，恢复到接口调用前的状态
     * </p>
     *
     * @param agentCode   应用code
     * @param req
     */
    public void batchUpdateInvoiceStatus(String agentCode, BatchUpdateInvoiceStatusReq req) {
        ResponseEntity<BaseResp> resp = restTemplate.postForEntity(
                baseUrl + "/cgi-bin/card/invoice/reimburse/updatestatusbatch?access_token={access_token}",
                req.build(), BaseResp.class,
                new ModelMap("access_token", getAccessToken(agentCode)));
        assertOK(resp);
    }
}
