package cn.superdesk.uniorder.controller.invoice.common;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.superdesk.libs.common.json.JsonUtils;
import cn.superdesk.uniorder.common.bizScene.invoice.common.InvoiceTypeScene;
import cn.superdesk.uniorder.common.enums.common.CommonEnabledEnum;
import cn.superdesk.uniorder.common.exception.utils.ExceptionUtils;
import cn.superdesk.uniorder.common.rest.response.R;
import cn.superdesk.uniorder.common.rest.response.ResponseResultOuterUtils;
import cn.superdesk.uniorder.controller.base.BaseController;
import cn.superdesk.uniorder.dao.entity.invoice.common.InvoiceType;
import cn.superdesk.uniorder.dto.param.invoice.common.InvoiceTypeCacheCriteria;
import cn.superdesk.uniorder.dto.param.invoice.common.InvoiceTypeOpCriteria;
import cn.superdesk.uniorder.dto.param.invoice.common.InvoiceTypeParam;
import cn.superdesk.uniorder.dto.param.invoice.common.InvoiceTypeQueryCriteria;
import cn.superdesk.uniorder.dto.vo.invoice.common.InvoiceTypeOpInvoiceSettingLoadingVo;
import cn.superdesk.uniorder.dto.vo.invoice.common.InvoiceTypePageQueryVo;
import cn.superdesk.uniorder.dubbo.consumer.invoice.common.InvoiceTypeDubboConsumerService;
import com.fasterxml.jackson.core.type.TypeReference;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * @Description:
 * @Author: linjinyu
 * @Email linjinyu@avic-s.com
 * @CreateDate: 2021-07-23 15:30:45
 * @UpdateUser: linjinyu
 * @UpdateDate: 2021-07-23 15:30:45
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Api(value = "系统设置-发票种类", tags = {"系统设置-发票种类"})
@Slf4j
@RestController
@RequestMapping("/invoiceType")
public class InvoiceTypeController extends BaseController {

    @Autowired
    private InvoiceTypeDubboConsumerService invoiceTypeDubboConsumerService;


    private <T> R<T> checkQueryCriteria(InvoiceTypeQueryCriteria queryCriteria, TypeReference<T> valueTypeRef) {

        if (ObjectUtil.isEmpty(queryCriteria.getSelectByModule())) {
            return ResponseResultOuterUtils.createErrorResult("500", "参数未指定");
        } else {

            if (!ArrayUtil.contains(
                    InvoiceTypeScene.modulesV2_1_Array_SceneParamCheck(),
                    queryCriteria.getSelectByModule())
            ) {
                return ResponseResultOuterUtils.createErrorResult("500", "非法参数");
            }
        }

        return ResponseResultOuterUtils.createSuccesResult();
    }

    private <T> R<T> checkOpCriteria(InvoiceTypeOpCriteria opCriteria, Class<T> elementType) {


//		客户结算("customerGoods", "客户结算"),
//		积分结算("customerCredit", "积分结算"),
//		供应商结算("supplierGoods", "供应商结算"),

        if (ObjectUtil.isEmpty(opCriteria.getSelectByModule())) {
            return ResponseResultOuterUtils.createErrorResult("500", "参数未指定");
        } else {

            if (!ArrayUtil.contains(
                    InvoiceTypeScene.modulesV2_1_Array_SceneParamCheck(),
                    opCriteria.getSelectByModule())
            ) {
                return ResponseResultOuterUtils.createErrorResult("500", "非法参数");
            }
        }

        if (ObjectUtil.isEmpty(opCriteria.getInvoiceTypeId())) {
            return ResponseResultOuterUtils.createErrorResult("500", "参数不能为空");
        }

        return ResponseResultOuterUtils.createSuccesResult();
    }


    private <T> R<T> checkAdvanceOpCriteria(InvoiceTypeOpCriteria opCriteria) {

        if (ObjectUtil.isEmpty(opCriteria.getSelectByModule())) {
            return ResponseResultOuterUtils.createErrorResult("500", "参数未指定");
        } else {

            if (!ArrayUtil.contains(
                    InvoiceTypeScene.modulesV2_1_Array_SceneParamCheck(),
                    opCriteria.getSelectByModule())
            ) {
                return ResponseResultOuterUtils.createErrorResult("500", "非法参数");
            }
        }


//		线下开票("offLine", "线下开票"),
//		深圳航信电子发票("szhtxxElectronicInvoice", "深圳航信电子发票"),
//      深圳航信纸质发票("szhtxxPaperInvoice", "深圳航信纸质发票"),
        if (ObjectUtil.isEmpty(opCriteria.getSelectByMode())) {
            return ResponseResultOuterUtils.createErrorResult("500", "参数未指定");
        } else {

            if (!ArrayUtil.contains(
                    InvoiceTypeScene.modesV2_1_Array_SceneParamCheck(),
                    opCriteria.getSelectByMode())
            ) {
                return ResponseResultOuterUtils.createErrorResult("500", "非法参数");
            }
        }

        if (ObjectUtil.isEmpty(opCriteria.getInvoiceTypeId())) {
            return ResponseResultOuterUtils.createErrorResult("500", "参数不能为空");
        }

        return ResponseResultOuterUtils.createSuccesResult();
    }


    /****************************************** 管理界面 start ******************************************/

    @ApiOperation(value = "系统设置-发票种类-列表分页-区分模块(包含 客户结算(customerGoods)|积分结算(customerCredit)|供应商结算(supplierGoods))-前端处理-按模块显示字段{customerGoods|customerCredit|supplierGoods}", notes = "积分结算2.1")
    @RequestMapping(value = "list", method = RequestMethod.POST)
    @ResponseBody
    public R<List<InvoiceTypePageQueryVo>> pageQuery(@RequestBody InvoiceTypeQueryCriteria queryCriteria) {

        // 写法 后端管理界面 不要求
        queryCriteria.setEnabled(null);

        log.info("pageQuery:\n{}", JsonUtils.toJson(queryCriteria));

        R<List<InvoiceTypePageQueryVo>> r = checkQueryCriteria(queryCriteria, new TypeReference<List<InvoiceTypePageQueryVo>>() {
        });

        if (r.getCode().equals("500")) {
            return r;
        }

        R<List<InvoiceTypePageQueryVo>> result = new R<>();

        // TODO 参数合法性判定


        List<Long> orderList = Arrays.asList(1L, 4L, 3L, 2L);

        queryCriteria.setBreakthroughEnabled(CommonEnabledEnum.启用.getKey());

        result = invoiceTypeDubboConsumerService.pageQuerySugarUp(queryCriteria, getToken());

        sortInvoiceTypeSelectVoTargetList1(orderList, result.getData());

        return result;
    }

    private static void sortInvoiceTypeSelectVoTargetList1(List<Long> orderList, List<InvoiceTypePageQueryVo> targetList) {

        targetList.sort(((o1, o2) -> {

            int io1 = orderList.indexOf(o1.getId());
            int io2 = orderList.indexOf(o2.getId());

            if (io1 != -1) {
                io1 = targetList.size() - io1;
            }

            if (io2 != -1) {
                io2 = targetList.size() - io2;
            }

            return io2 - io1;
        }));
    }

    /****************************************** 管理界面   end ******************************************/


    /****************************************** 操作类 start ******************************************/

    @ApiOperation(value = "设置默认-发票种类-操作-区分模块", notes = "积分结算2.1")
    @PostMapping("/opSetDefault")
    @ResponseBody
    public R<String> opSetDefault(@RequestBody InvoiceTypeOpCriteria opCriteria) {

        R<String> r = checkOpCriteria(opCriteria, String.class);

        if (r.getCode().equals("500")) {
            return r;
        }

        try {

            int ret = invoiceTypeDubboConsumerService.opSetDefault(opCriteria, getToken());
            if (ret > 0) {
                return ResponseResultOuterUtils.createSuccesResult();
            } else {
                return ResponseResultOuterUtils.createErrorResult("500", "操作失败");
            }

        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
            return ResponseResultOuterUtils.createErrorResult("500", StrUtil.format("{}:{}", e.hashCode(), e.getMessage()));
        }
    }

    @ApiOperation(value = "取消默认-发票种类-操作-区分模块", notes = "积分结算2.1")
    @PostMapping("/opSetNormal")
    @ResponseBody
    public R<String> opSetNormal(@RequestBody InvoiceTypeOpCriteria opCriteria) {

        R<String> r = checkOpCriteria(opCriteria, String.class);

        if (r.getCode().equals("500")) {
            return r;
        }

        try {

            int ret = invoiceTypeDubboConsumerService.opSetNormal(opCriteria, getToken());
            if (ret > 0) {
                return ResponseResultOuterUtils.createSuccesResult();
            } else {
                return ResponseResultOuterUtils.createErrorResult("500", "操作失败");
            }

        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
            return ResponseResultOuterUtils.createErrorResult("500", StrUtil.format("{}:{}", e.hashCode(), e.getMessage()));
        }
    }

    @ApiOperation(value = "启用-发票种类-操作-区分模块", notes = "积分结算2.1")
    @PostMapping("/opSetEnable")
    @ResponseBody
    public R<String> opSetEnable(@RequestBody InvoiceTypeOpCriteria opCriteria) {

        R<String> r = checkOpCriteria(opCriteria, String.class);

        if (r.getCode().equals("500")) {
            return r;
        }

        try {

            int ret = invoiceTypeDubboConsumerService.opSetEnable(opCriteria, getToken());
            if (ret > 0) {
                return ResponseResultOuterUtils.createSuccesResult();
            } else {
                return ResponseResultOuterUtils.createErrorResult("500", "操作失败");
            }

        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
            return ResponseResultOuterUtils.createErrorResult("500", StrUtil.format("{}:{}", e.hashCode(), e.getMessage()));
        }
    }

    @ApiOperation(value = "停用-发票种类-操作-区分模块", notes = "积分结算2.1")
    @PostMapping("/opSetDisable")
    @ResponseBody
    public R<String> opSetDisable(@RequestBody InvoiceTypeOpCriteria opCriteria) {

        R<String> r = checkOpCriteria(opCriteria, String.class);

        if (r.getCode().equals("500")) {
            return r;
        }

        try {

            int ret = invoiceTypeDubboConsumerService.opSetDisable(opCriteria, getToken());
            if (ret > 0) {
                return ResponseResultOuterUtils.createSuccesResult();
            } else {
                return ResponseResultOuterUtils.createErrorResult("500", "操作失败");
            }

        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
            return ResponseResultOuterUtils.createErrorResult("500", StrUtil.format("{}:{}", e.hashCode(), e.getMessage()));
        }
    }

    /****************************************** 操作类 start ******************************************/


    /****************************************** 操作类 进阶 start ******************************************/

    @ApiOperation(value = "设置默认-发票种类-开票设置-进阶操作-区分模块", notes = "积分结算2.1")
    @PostMapping("/invoiceSetting/opSetDefault")
    @ResponseBody
    public R<String> opInvoiceSettingSetDefault(@RequestBody InvoiceTypeOpCriteria opCriteria) {

        R<String> r = checkAdvanceOpCriteria(opCriteria);

        if (r.getCode().equals("500")) {
            return r;
        }

        try {

            int ret = invoiceTypeDubboConsumerService.opInvoiceSettingSetDefault(opCriteria, getToken());
            if (ret > 0) {
                return ResponseResultOuterUtils.createSuccesResult();
            } else {
                return ResponseResultOuterUtils.createErrorResult("500", "操作失败");
            }

        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
            return ResponseResultOuterUtils.createErrorResult("500", StrUtil.format("{}:{}", e.hashCode(), e.getMessage()));
        }
    }

    @ApiOperation(value = "取消默认-发票种类-开票设置-进阶操作-区分模块", notes = "积分结算2.1")
    @PostMapping("/invoiceSetting/opSetNormal")
    @ResponseBody
    public R<String> opInvoiceSettingSetNormal(@RequestBody InvoiceTypeOpCriteria opCriteria) {

        R<String> r = checkAdvanceOpCriteria(opCriteria);

        if (r.getCode().equals("500")) {
            return r;
        }

        try {

            int ret = invoiceTypeDubboConsumerService.opInvoiceSettingSetNormal(opCriteria, getToken());
            if (ret > 0) {
                return ResponseResultOuterUtils.createSuccesResult();
            } else {
                return ResponseResultOuterUtils.createErrorResult("500", "操作失败");
            }

        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
            return ResponseResultOuterUtils.createErrorResult("500", StrUtil.format("{}:{}", e.hashCode(), e.getMessage()));
        }
    }

    @ApiOperation(value = "开通|启用-发票种类-开票设置-开票方式-区分模块", notes = "积分结算2.1")
    @PostMapping("/invoiceSetting/opSetEnable")
    @ResponseBody
    public R<String> opInvoiceSettingSetEnable(@RequestBody InvoiceTypeOpCriteria opCriteria) {

        R<String> r = checkAdvanceOpCriteria(opCriteria);

        if (r.getCode().equals("500")) {
            return r;
        }

        try {

            int ret = invoiceTypeDubboConsumerService.opInvoiceSettingSetEnable(opCriteria, getToken());
            if (ret > 0) {
                return ResponseResultOuterUtils.createSuccesResult();
            } else {
                return ResponseResultOuterUtils.createErrorResult("500", "操作失败");
            }

        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
            return ResponseResultOuterUtils.createErrorResult("500", StrUtil.format("{}:{}", e.hashCode(), e.getMessage()));
        }
    }

    @ApiOperation(value = "停用|禁用-发票种类-开票设置-开票方式-区分模块", notes = "积分结算2.1")
    @PostMapping("/invoiceSetting/opSetDisable")
    @ResponseBody
    public R<String> opInvoiceSettingSetDisable(@RequestBody InvoiceTypeOpCriteria opCriteria) {

        R<String> r = checkAdvanceOpCriteria(opCriteria);

        if (r.getCode().equals("500")) {
            return r;
        }

        try {

            int ret = invoiceTypeDubboConsumerService.opInvoiceSettingSetDisable(opCriteria, getToken());
            if (ret > 0) {
                return ResponseResultOuterUtils.createSuccesResult();
            } else {
                return ResponseResultOuterUtils.createErrorResult("500", "操作失败");
            }

        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
            return ResponseResultOuterUtils.createErrorResult("500", StrUtil.format("{}:{}", e.hashCode(), e.getMessage()));
        }
    }

    /**
     * 1.2.2.2 【开票设置】_纸质专用发票_积分结算
     *
     * @param opCriteria
     * @return
     */
    @ApiOperation(value = "开票设置(装载)-发票种类-操作-区分模块", notes = "积分结算2.1")
    @PostMapping("/opInvoiceSettingLoading")
    @ResponseBody
    public R<InvoiceTypeOpInvoiceSettingLoadingVo> opInvoiceSettingLoading(@RequestBody InvoiceTypeOpCriteria opCriteria) {

        R<InvoiceTypeOpInvoiceSettingLoadingVo> r = checkOpCriteria(opCriteria, InvoiceTypeOpInvoiceSettingLoadingVo.class);

        if (r.getCode().equals("500")) {
            return r;
        }

        if (!opCriteria.getSelectByModule().equals("customerCredit")) {
            return ResponseResultOuterUtils.createErrorResult("500", "目前只有模块[积分结逄]支持开票设置");
        }

        try {

            return ResponseResultOuterUtils.createSuccesResult("200", invoiceTypeDubboConsumerService.opInvoiceSettingLoading(opCriteria, getToken()));


        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
            return ResponseResultOuterUtils.createErrorResult("500", StrUtil.format("{}:{}", e.hashCode(), e.getMessage()));
        }
    }

    /****************************************** 操作类 进阶   end ******************************************/


    @ApiOperation(value = "系统设置-发票种类-按id查询")
    @RequestMapping(value = "{id}", method = RequestMethod.GET)
    @ResponseBody
    public R<List<InvoiceType>> getById(@PathVariable("id") long id) {

        R<List<InvoiceType>> result = new R<>();

        // TODO 参数合法性判定

        InvoiceType entity = invoiceTypeDubboConsumerService.findInvoiceTypeById(id);

        List<InvoiceType> data = new ArrayList<>();
        data.add(entity);

        result.setData(data);

        return result;
    }

    @ApiOperation(value = "系统设置-发票种类-新增")
    @RequestMapping(value = "add", method = RequestMethod.POST)
    @ResponseBody
    public R<String> addInvoiceType(@RequestBody InvoiceTypeParam param) {

        log.info("addInvoiceType:\n{}", JsonUtils.toJson(param));


        // TODO 参数合法性判定

        invoiceTypeDubboConsumerService.addInvoiceType(param);

        return new R<>("200", "操作成功", true);
    }

    @ApiOperation(value = "系统设置-发票种类-更新")
    @RequestMapping(value = "update", method = RequestMethod.POST)
    @ResponseBody
    public R<String> updateInvoiceType(@RequestBody InvoiceTypeParam param) {

        log.info("updateInvoiceType:\n{}", JsonUtils.toJson(param));

        invoiceTypeDubboConsumerService.updateInvoiceType(param);

        return new R<>("200", "操作成功", true);
    }

    @ApiOperation(value = "系统设置-发票种类-删除")
    @RequestMapping(value = "delete/{id}", method = RequestMethod.POST)
    @ResponseBody
    public R<String> deleteInvoiceType(@PathVariable("id") long id) {

        // TODO 参数合法性判定

        invoiceTypeDubboConsumerService.deleteInvoiceType(id);

        return new R<>("200", "操作成功", true);
    }

    @ApiOperation(value = "系统设置-发票种类-批量删除")
    @RequestMapping(value = "delete_ids", method = RequestMethod.POST)
    @ResponseBody
    public R<String> deleteIdsInvoiceType(@RequestParam(value = "ids") long[] ids) {

        log.info(JsonUtils.toJson(ids));

        for (long id : ids) {
            invoiceTypeDubboConsumerService.deleteInvoiceType(id);
        }

        return new R<>("200", "操作成功", true);

    }

    /****************************************** 缓存 start ******************************************/

    /**
     * http://192.168.6.223:8089/web/invoiceType/cacheInit
     *
     * @return
     */
    @ApiOperation(value = "系统设置-发票种类-缓存-cacheInit")
    @RequestMapping(value = "cacheInit", method = RequestMethod.POST)
    @ResponseBody
    public R<String> cacheInit(@RequestBody InvoiceTypeCacheCriteria criteria) {

        invoiceTypeDubboConsumerService.cacheInit(criteria);
        return new R<>("200", "cacheInit 操作成功", true);

    }

    @ApiOperation(value = "系统设置-发票种类-缓存-cacheRefresh")
    @RequestMapping(value = "cacheRefresh", method = RequestMethod.POST)
    @ResponseBody
    public R<String> cacheRefresh(@RequestBody InvoiceTypeCacheCriteria criteria) {

        invoiceTypeDubboConsumerService.cacheRefresh(criteria);
        return new R<>("200", "cacheRefresh 操作成功", true);

    }

    @ApiOperation(value = "系统设置-发票种类-缓存-cacheRemove")
    @RequestMapping(value = "cacheRemove", method = RequestMethod.POST)
    @ResponseBody
    public R<String> cacheRemove(@RequestBody InvoiceTypeCacheCriteria criteria) {

        invoiceTypeDubboConsumerService.cacheRemove(criteria);
        return new R<>("200", "cacheRemove 操作成功", true);

    }


    /**
     * @param criteria
     * @return
     */
    @ApiOperation(value = "系统设置-发票种类-缓存-cacheGet")
    @RequestMapping(value = "cacheGet", method = RequestMethod.POST)
    @ResponseBody
    public R<String> cacheGet(@RequestBody InvoiceTypeCacheCriteria criteria) {

//		{
//			"hashTable": "relation:invoice_type",
//				"hashTableKeyField": "type_name",
//				"keyField": "增值税专票"
//		}

        String hashTable = criteria.getHashTable();
        String keyField  = criteria.getKeyField();

        log.info("{}{}", hashTable, keyField);

        String responseData = invoiceTypeDubboConsumerService.cacheGet(criteria);
        return new R<>("200", "操作成功", responseData);

    }
}
