package pwc.taxtech.atms.controller;

import com.alibaba.fastjson.JSON;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.nutz.lang.Lang;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.thymeleaf.util.StringUtils;
import pwc.taxtech.atms.dpo.PagingDto;
import pwc.taxtech.atms.dto.OperationResultDto;
import pwc.taxtech.atms.dto.PagingResultDto;
import pwc.taxtech.atms.dto.customer.CustomerDto;
import pwc.taxtech.atms.dto.customer.CustomerValidateInfoDto;
import pwc.taxtech.atms.dto.vatdto.CustomsInvoiceDto;
import pwc.taxtech.atms.dto.vatdto.CustomsInvoiceFilter;
import pwc.taxtech.atms.dto.vatdto.JsonCustomsInvoice;
import pwc.taxtech.atms.service.CustomerService;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 */
@RestController
@RequestMapping("/api/v1/customer")
public class CustomerController {

    private static final Logger logger = LoggerFactory.getLogger(CustomerController.class);

    @Autowired
    private CustomerService customerService;

    @ApiOperation(value = "财务数据客户增加")
    // @ApiImplicitParam(name = "customerDtoList", value = "customerDto List",
    // required = true, dataType = "List<CustomerDto>")
    @RequestMapping(value = "/AddRange", method = RequestMethod.POST)
    public @ResponseBody
    List<OperationResultDto<CustomerDto>> addRange(
            @RequestBody List<CustomerDto> customerDtoList) {
        logger.debug("CustomerController /AddRange");
        return customerService.addRange(customerDtoList);
    }

    @ApiOperation(value = "财务数据账套下客户查询")
    @ApiImplicitParam(name = "id", value = "记录Id", required = true, dataType = "java.lang.String")
    @RequestMapping(value = "/getByID", method = RequestMethod.GET)
    public @ResponseBody
    CustomerValidateInfoDto getById(@RequestParam(name = "ID") String setId) {
        logger.debug("enter getByID");
        return customerService.getByEnterpriseAccountSetId(setId);
    }

    @ApiOperation(value = "财务数据所有客户查询")
    @RequestMapping(value = "/get", method = RequestMethod.GET)
    public @ResponseBody
    List<CustomerDto> getCustomer() {
        logger.debug("enter getCustomer");
        return customerService.getCustomer();
    }

    @ApiOperation(value = "财务数据客户删除")
    // @ApiImplicitParam(name = "customerDtoList", value = "customerDto List",
    // required = true, dataType = "List<CustomerDto>")
    @RequestMapping(value = "/DeleteRange", method = RequestMethod.POST)
    public @ResponseBody
    OperationResultDto<String> deleteRange(@RequestBody List<CustomerDto> customerDtoList) {
        logger.debug("enter deleteRange");
        return customerService.deleteRange(customerDtoList);
    }

    @ApiOperation(value = "财务数据客户修改")
    // @ApiImplicitParam(name = "customerDtoList", value = "customerDto List",
    // required = true, dataType = "List<CustomerDto>")
    @RequestMapping(value = "/UpdateRange", method = RequestMethod.POST)
    public @ResponseBody
    List<OperationResultDto<CustomerDto>> updateRange(
            @RequestBody List<CustomerDto> customerDtoList) {
        logger.debug("enter updateRange");
        return customerService.updateRange(customerDtoList);
    }

    @ApiOperation(value = "批量上传账套下客户列表")
    // @ApiImplicitParam(name = "file", value = "file", required = true, dataType =
    // "CommonsMultipartFile")
    @RequestMapping(value = "/Upload", method = RequestMethod.POST)
    public @ResponseBody
    Object upload(@RequestParam(value = "file", required = false) CommonsMultipartFile inputFile,
                  @RequestParam(value = "enterpriseAccountId", required = false) String enterpriseAccountId,
                  @RequestParam(value = "action", required = false) String action) {
        logger.debug("enter upload");
        logger.debug("enterpriseAccountId: {}", enterpriseAccountId);
        logger.debug("action: {}", action);

        if (inputFile == null || inputFile.getSize() <= 0) {
            OperationResultDto<?> operationResultDto = new OperationResultDto<>();
            operationResultDto.setResult(false);
            operationResultDto.setResultMsg("NoFile");
            logger.warn("File is empty");
            return operationResultDto;
        }
        logger.debug("file name: " + inputFile.getOriginalFilename());
        InputStream input = null;
        try {
            input = inputFile.getInputStream();
        } catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
        return customerService.upload(input, inputFile.getOriginalFilename(), action, enterpriseAccountId);
    }

    @RequestMapping(value = "GetCustomsInvoiceDataForDisplay", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity GetCustomsInvoiceDataForDisplay(@RequestParam Integer fromPeriod, @RequestParam Integer toPeriod,
                                                          @RequestParam String criteria, @RequestParam String pagination) {
        CustomsInvoiceFilter filter = new CustomsInvoiceFilter();
        if (!StringUtils.isEmpty(criteria) && criteria != "null")
            filter = JSON.parseObject(criteria, CustomsInvoiceFilter.class);
        else
            filter = null;

        // PAGINATION INFORMATION:
        PagingDto paging = new PagingDto();
        if (!StringUtils.isEmpty(pagination) && pagination != "null") {
            paging = JSON.parseObject(pagination, PagingDto.class);
        } else
            paging = null;

        String passResponse = ConvertCustomsInvoiceDataToJson(fromPeriod, toPeriod, filter, paging);
        return ResponseEntity.ok(passResponse);
    }

    private String ConvertCustomsInvoiceDataToJson(int fromPeriod, int toPeriod, CustomsInvoiceFilter filter, PagingDto pagination) {
        String result = "";
        List<CustomsInvoiceDto> balanceList = customerService.GetCustomsInvoicesByPeriodIds(fromPeriod, toPeriod);

        if (filter != null && !balanceList.isEmpty())
            balanceList = FilterCustomsInvoiceDataList(filter, balanceList);

        if (pagination != null) {
            int pageAskingFor = 0;

            if (pagination.getPageIndex() > 0)
                pageAskingFor = pagination.getPageIndex() - 1;
            // Update Total Counts:
            pagination.setTotalCount(balanceList.size());
            balanceList = balanceList.subList(pageAskingFor * pagination.getPageSize(), pageAskingFor * pagination.getPageSize() + pagination.getPageSize());
        }

        List<JsonCustomsInvoice> recordList = new ArrayList<>();
        JsonCustomsInvoice record;

        int indexNumber = 1;
        for (CustomsInvoiceDto item : balanceList) {
            record = new JsonCustomsInvoice();
            record.RecordNumber = indexNumber + "";
            record.CustomsId = item.getCustomsId();
            record.PayNum = item.getPayNum();
            record.IssueDate = new SimpleDateFormat("yyyy-MM-dd").format(item.getIssueDate());
            record.InvoiceTaxAmount = item.getInvoiceTaxAmount() != null ? item.getInvoiceTaxAmount().toString() : "0.00";
            record.InvoiceAmount = item.getInvoiceAmount() != null ? item.getInvoiceAmount().toString() : "0.00";
            record.AuditResult = item.getAuditResult();
            record.PeriodId = item.getPeriodId();
            recordList.add(record);
            indexNumber++;
        }
        PagingResultDto<JsonCustomsInvoice> listWithPaging = new PagingResultDto<>();
        listWithPaging.setPageInfo(pagination);
        listWithPaging.setList(recordList);

        result = JSON.toJSONString(listWithPaging);
        return result;
    }

    private List<CustomsInvoiceDto> FilterCustomsInvoiceDataList(CustomsInvoiceFilter filter, List<CustomsInvoiceDto> dataList) {
        // Do filters:
        if (!dataList.isEmpty()) {
            // period:
            //if (filter.getPeriodFrom ()!=null&& filter.PeriodFrom.Value > 0)
            //    dataList = dataList.stream().filter((-=> x.PeriodId.Value == filter.getPeriodFrom().doubleValue().ToList();


            // payment number  -- Added Like operation

            if (!StringUtils.isEmpty(filter.getPayNum())) {
                String[] names = filter.getPayNum().split(" ");
                List<CustomsInvoiceDto> ds = new ArrayList<>();
                for (String name : names) {
                    ds.addAll(dataList.stream().filter(x -> x.getPayNum().contains(name)).collect(Collectors.toList()));
                }
                dataList = ds;
            }

            // tax amount
            if (filter.getTaxAmountFrom() != null || filter.getTaxAmountTo() != null) {
                //both start and end dates are there
                if (filter.getTaxAmountFrom() != null && filter.getTaxAmountTo() != null)
                    dataList = dataList.stream().filter(x -> x.getInvoiceAmount() != null && (filter.getTaxAmountFrom().doubleValue()
                            <= x.getInvoiceTaxAmount().doubleValue() && filter.getTaxAmountTo().doubleValue() >= x.getInvoiceTaxAmount().doubleValue()))
                            .collect(Collectors.toList());
                else if (filter.getTaxAmountFrom() != null)
                    dataList = dataList.stream().filter(x -> x.getInvoiceTaxAmount() != null && filter.getTaxAmountFrom()
                            .doubleValue() <= x.getInvoiceTaxAmount().doubleValue()).collect(Collectors.toList());
                else
                    dataList = dataList.stream().filter(x -> x.getInvoiceTaxAmount() != null && filter.getTaxAmountTo()
                            .doubleValue() >= x.getInvoiceTaxAmount().doubleValue()).collect(Collectors.toList());
            }

            // amount

            if (filter.getInvoiceAmountFrom() != null || filter.getInvoiceAmountTo() != null) {
                //both start and end dates are there
                if (filter.getInvoiceAmountFrom() != null && filter.getInvoiceAmountTo() != null)
                    dataList = dataList.stream().filter(x -> x.getInvoiceAmount() != null && (filter.getInvoiceAmountFrom().doubleValue()
                            <= x.getInvoiceAmount().doubleValue() && filter.getInvoiceAmountTo().doubleValue()
                            >= x.getInvoiceAmount().doubleValue())).collect(Collectors.toList());
                else if (filter.getInvoiceAmountFrom() != null)
                    dataList = dataList.stream().filter(x -> x.getInvoiceAmount() != null && filter.getInvoiceAmountFrom().doubleValue()
                            <= x.getInvoiceAmount().doubleValue()).collect(Collectors.toList());
                else
                    dataList = dataList.stream().filter(x -> x.getInvoiceAmount() != null && filter.getInvoiceAmountTo().doubleValue()
                            >= x.getInvoiceAmount().doubleValue()).collect(Collectors.toList());
            }


            // invoice start date and/or invoice end date
            if (filter.getInvoiceStartDate() != null || filter.getInvoiceEndDate() != null) {
                //both start and end dates are there
                if (filter.getInvoiceStartDate() != null && filter.getInvoiceEndDate() != null)
                    dataList = dataList.stream().filter(x -> x.getIssueDate() != null && (filter.getInvoiceStartDate()
                            .before(x.getIssueDate()) && filter.getInvoiceEndDate().after(x.getIssueDate()))).collect(Collectors.toList());
                else if (filter.getInvoiceStartDate() != null)
                    dataList = dataList.stream().filter(x -> x.getIssueDate() != null && filter.getInvoiceStartDate()
                            .before(x.getIssueDate())).collect(Collectors.toList());
                else
                    dataList = dataList.stream().filter(x -> x.getIssueDate() != null && filter.getInvoiceEndDate()
                            .after(x.getIssueDate())).collect(Collectors.toList());
            }

        }

        return dataList;
    }


}