package com.gci.boot.modules.finance.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gci.boot.annotation.Query.handle.QueryGenerator;
import com.gci.boot.common.log.annotation.AddSysLog;
import com.gci.boot.common.util.StringUtil;
import com.gci.boot.common.vo.Result;
import com.gci.boot.modules.finance.entity.BaseFinance;
import com.gci.boot.modules.finance.entity.FinanceVehicleCost;
import com.gci.boot.modules.finance.entity.MeasureResult;
import com.gci.boot.modules.finance.entity.VehicleCost;
import com.gci.boot.modules.finance.service.IBaseFinanceService;
import com.gci.boot.modules.finance.service.IFinanceVehicleCostService;
import com.gci.boot.modules.finance.service.IMeasureResultService;
import com.gci.boot.modules.finance.service.IVehicleCostService;
import com.gci.boot.modules.finance.vo.*;
import com.gci.boot.modules.projects.entity.Projects;
import com.gci.boot.modules.projects.service.IProjectsService;
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.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Api(tags="财务测算")
@RestController
@RequestMapping("/finance/calculate")
@Slf4j
public class FinanceCalculateController {

    @Autowired
    private IBaseFinanceService baseFinanceService;
    @Autowired
    private IProjectsService projectsService;
    @Autowired
    private IFinanceVehicleCostService financeVehicleCostService;
    @Autowired
    private IMeasureResultService measureResultService;
    @Autowired
    private IVehicleCostService vehicleCostService;

    @PostMapping(value = "/test")
    public Result<?> test(@RequestBody BaseFinance baseFinance) {
        Object object =  baseFinanceService.calculate(baseFinance);
        return Result.ok(object);
    }

    @AddSysLog("财务测算-测算")
    @ApiOperation(value="财务测算-测算", notes="财务测算-测算")
    @PostMapping(value = "/calculate")
    public Result<?> calculate(@RequestBody BaseFinance baseFinance) {
        if(baseFinance.getOverheadSharing().doubleValue() == 0){
            return Result.error(101,"管理分担费用(%)不能为零!");
        }
        CalculateResultObjectVO object =  baseFinanceService.calculate(baseFinance);
        return Result.ok(object);
    }

    @AddSysLog("财务测算-获取详情")
    @ApiOperation(value="财务测算-获取详情", notes="财务测算-获取详情")
    @GetMapping(value = "/getById")
    public Result<?> getById(String id) {
        DetailObjectVO object = new DetailObjectVO();
        object = baseFinanceService.getDetailById(id);
        return Result.ok(object);
    }

    @AddSysLog("财务测算-保存")
    @ApiOperation(value="财务测算-保存", notes="财务测算-保存")
    @PostMapping(value = "/add")
    public Result<?> add(@RequestBody DetailObjectVO detailObjectVO) {
        String checkStr = StringUtil.checkString(detailObjectVO.getProjectId(),100);
        if(StrUtil.isNotBlank(checkStr)){
            return Result.error(101,"项目" + checkStr);
        }
        if(CollectionUtil.isEmpty(detailObjectVO.getVehicleCostList())){
            return Result.error(101,"缺少车辆信息!");
        }
        if(Objects.isNull(detailObjectVO.getCalculateObject())){
            return Result.error(101,"缺少测算详情,请先测算再保存!");
        }

        String str =  baseFinanceService.addDetail(detailObjectVO);
        return Result.ok(str);
    }

    /**
     *   删除
     */
    @AddSysLog("财务测算-删除")
    @ApiOperation(value="财务测算-删除", notes="财务测算-删除")
    @DeleteMapping(value = "/delete")
    public Result<?> delete(@RequestParam(name="id",required=true) String id) {
        baseFinanceService.deleteDetailById(id);
        return Result.ok("删除成功！");
    }

    /**
     * 分页列表查询
     *
     */
    @AddSysLog("财务测算-分页列表查询")
    @ApiOperation(value="财务测算-分页列表查询", notes="财务测算-分页列表查询")
    @GetMapping(value = "/list")
    public Result<?> queryPageList(CalculateParamVO paramVO,
                                   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
                                   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
                                   HttpServletRequest req ) {
        Page<CalculateListVO> page = new Page<CalculateListVO>(pageNo, pageSize);

        IPage<VehicleCost> pageList = baseFinanceService.getCalcutatePage(page, paramVO);
        return Result.ok(pageList);
    }

    /**
     * 成本录入列表
     *
     */
    @AddSysLog("财务测算-获取成本录入列表")
    @ApiOperation(value="财务测算-成本录入列表", notes="财务测算-成本录入列表")
    @GetMapping(value = "/costList")
    public Result<?> queryCostList() {
        List<VehicleCost> pageList = vehicleCostService.list();
        return Result.ok(pageList);
    }

    /**
     * 导出
     * @return
     */
    @AddSysLog("财务测算-导出")
    @GetMapping("/export")
    public Result<?> export(HttpServletResponse response, String id) throws IOException {
        try (OutputStream output = response.getOutputStream()){
            String fileName = "财务测算.xlsx";
            try {
                fileName = URLEncoder.encode(fileName, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ";" + "filename*=utf-8''" + fileName);
            // 提前构建输出流
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
            // 构建sheet页
            WriteSheet writeSheet = EasyExcel.writerSheet("财务测算")
                    .registerWriteHandler(new SimpleColumnWidthStyleStrategy(20)).needHead(Boolean.FALSE).build();
            //输出内容
            DetailObjectVO object = baseFinanceService.getDetailById(id);
            // 多次写入
            List<List<String>> contentHeader1 = this.buildHeader1();
            WriteTable writeTable1 = EasyExcel.writerTable( 0).needHead(Boolean.TRUE).head(contentHeader1).build();
            List<List<Object>> body1 = this.buildBody1(object);
            excelWriter.write(body1, writeSheet, writeTable1);

            List<List<String>> contentHeader2 = this.buildHeader2();
            WriteTable writeTable2 = EasyExcel.writerTable( 1).needHead(Boolean.TRUE).head(contentHeader2).build();
            List<List<Object>> body2 = this.buildBody2(object);
            excelWriter.write(body2, writeSheet, writeTable2);


            List<List<String>> contentHeader3 = this.buildHeader3();
            List<List<String>> nameHeader3 = contentHeader3.stream().map(item -> Collections.singletonList("测算结果")).collect(Collectors.toList());
            WriteTable writeTable03 = EasyExcel.writerTable(2).needHead(Boolean.TRUE).head(nameHeader3).build();
            excelWriter.write((Collection<?>) null, writeSheet, writeTable03);
            WriteTable writeTable3 = EasyExcel.writerTable( 3).needHead(Boolean.TRUE).head(contentHeader3).build();
            List<List<Object>> body3 = this.buildBody3(object);
            excelWriter.write(body3, writeSheet, writeTable3);

            List<List<String>> contentHeader4 = this.buildHeader4();
            List<List<String>> nameHeader4 = contentHeader4.stream().map(item -> Collections.singletonList("租金收入")).collect(Collectors.toList());
            WriteTable writeTable04 = EasyExcel.writerTable(4).needHead(Boolean.TRUE).head(nameHeader4).build();
            excelWriter.write((Collection<?>) null, writeSheet, writeTable04);
            WriteTable writeTable4 = EasyExcel.writerTable( 5).needHead(Boolean.TRUE).head(contentHeader4).build();
            List<List<Object>> body4 = this.buildBody4(object);
            excelWriter.write(body4, writeSheet, writeTable4);

            List<List<String>> contentHeader5 = this.buildHeader5();
            List<List<String>> nameHeader5 = contentHeader5.stream().map(item -> Collections.singletonList("管理、运维、保险费用（单位：万元）")).collect(Collectors.toList());
            WriteTable writeTable05 = EasyExcel.writerTable(6).needHead(Boolean.TRUE).head(nameHeader5).build();
            excelWriter.write((Collection<?>) null, writeSheet, writeTable05);
            WriteTable writeTable5 = EasyExcel.writerTable( 7).needHead(Boolean.TRUE).head(contentHeader5).build();
            List<List<Object>> body5 = this.buildBody5(object);
            excelWriter.write(body5, writeSheet, writeTable5);

            List<List<String>> contentHeader6 = this.buildHeader5();
            List<List<String>> nameHeader6 = contentHeader6.stream().map(item -> Collections.singletonList("收入与税金表（单位：万元）")).collect(Collectors.toList());
            WriteTable writeTable06 = EasyExcel.writerTable(8).needHead(Boolean.TRUE).head(nameHeader6).build();
            excelWriter.write((Collection<?>) null, writeSheet, writeTable06);
            WriteTable writeTable6 = EasyExcel.writerTable( 9).needHead(Boolean.TRUE).head(contentHeader6).build();
            List<List<Object>> body6 = this.buildBody6(object);
            excelWriter.write(body6, writeSheet, writeTable6);

            List<List<String>> contentHeader7 = this.buildHeader5();
            List<List<String>> nameHeader7 = contentHeader7.stream().map(item -> Collections.singletonList("成本与利润表（单位：万元）")).collect(Collectors.toList());
            WriteTable writeTable07 = EasyExcel.writerTable(10).needHead(Boolean.TRUE).head(nameHeader7).build();
            excelWriter.write((Collection<?>) null, writeSheet, writeTable07);
            WriteTable writeTable7 = EasyExcel.writerTable( 11).needHead(Boolean.TRUE).head(contentHeader7).build();
            List<List<Object>> body7 = this.buildBody7(object);
            excelWriter.write(body7, writeSheet, writeTable7);

            excelWriter.finish();

        } catch (IOException e) {
            return Result.error("导出错误！");
        }
        return Result.ok();
    }

    public List<List<String>> buildHeader1() {
        List<List<String>> header = new ArrayList<>();
        header.add(Collections.singletonList("项目"));
        header.add(Collections.singletonList("租赁年限"));
        header.add(Collections.singletonList("融资比例（%）"));
        header.add(Collections.singletonList("融资利率（%）"));
        header.add(Collections.singletonList("管理费用分担（%）"));
        return header;
    }
    //基本信息
    public List<List<Object>> buildBody1(DetailObjectVO object) {
//        Projects project = projectsService.getById(object.getProjectId());

        List<List<Object>> body = new ArrayList<>();
        List<Object> objectList = new ArrayList<>();
        objectList.add(object.getProjectId());
        objectList.add(object.getYearLimit());
        objectList.add(object.getFinancingRatio());
        objectList.add(object.getFinancingRate());
        objectList.add(object.getOverheadSharing());
        body.add(objectList);
        return body;
    }

    public List<List<String>> buildHeader2() {
        List<List<String>> header = new ArrayList<>();
        header.add(Arrays.asList("车型", "车型"));
        header.add(Arrays.asList("单价(万元)", "单价(万元)"));
        header.add(Arrays.asList("上牌费用/购置税(万元)", "上牌费用/购置税(万元)"));
        header.add(Arrays.asList("保险(万元/台/年)", "保险(万元/台/年)"));
        header.add(Arrays.asList("维修及易损件(万元)", "维修及易损件(万元)"));
        header.add(Arrays.asList("保养(万元)", "保养(万元)"));
        header.add(Arrays.asList("年审(万元)", "年审(万元)"));
        header.add(Arrays.asList("租赁报价(万元/月/台)", "第一年"));
        header.add(Arrays.asList("租赁报价(万元/月/台)", "第二年"));
        header.add(Arrays.asList("租赁报价(万元/月/台)", "第三年"));
        header.add(Arrays.asList("租赁报价(万元/月/台)", "第四年"));
        header.add(Arrays.asList("租赁报价(万元/月/台)", "第五年"));
        header.add(Arrays.asList("租赁报价(万元/月/台)", "第六年"));
        header.add(Arrays.asList("租赁报价(万元/月/台)", "第七年"));
        header.add(Arrays.asList("租赁报价(万元/月/台)", "第八年"));
        header.add(Arrays.asList("数量", "数量"));
        header.add(Arrays.asList("残值(万元/台)", "残值(万元/台)"));
        return header;
    }
    //车辆信息
    public List<List<Object>> buildBody2(DetailObjectVO object) {
        List<FinanceVehicleCost> vehicleList = object.getVehicleCostList();
        List<List<Object>> body = new ArrayList<>();
        for(FinanceVehicleCost vehicle : vehicleList){
            List<Object> objectList = new ArrayList<>();
            objectList.add(vehicle.getVehicleType());
            objectList.add(vehicle.getUnitPrice());
            objectList.add(vehicle.getPurchaseTax());
            objectList.add(vehicle.getInsurance());
            objectList.add(vehicle.getRepair());
            objectList.add(vehicle.getUpkeep());
            objectList.add(vehicle.getAnnualAudit());
            objectList.add(vehicle.getOneYear());
            objectList.add(vehicle.getTwoYear());
            objectList.add(vehicle.getThreeYear());
            objectList.add(vehicle.getFourYear());
            objectList.add(vehicle.getFiveYear());
            objectList.add(vehicle.getSixYear());
            objectList.add(vehicle.getSevenYear());
            objectList.add(vehicle.getEightYear());
            objectList.add(vehicle.getQuantity());
            objectList.add(vehicle.getSalvageValue());
            body.add(objectList);
        }
        return body;
    }

    public List<List<String>> buildHeader3() {
        List<List<String>> header = new ArrayList<>();
        header.add(Collections.singletonList("购车成本回收期(年)"));
        header.add(Collections.singletonList("融资成本(万元)"));
        header.add(Collections.singletonList("内部收益率(%)"));
        header.add(Collections.singletonList("实缴增值税及附加(万元)"));
        header.add(Collections.singletonList("所得税(万元)"));
        header.add(Collections.singletonList("净利润(万元)"));
        header.add(Collections.singletonList("残值(万元)"));
        return header;
    }
    //测算结果
    public List<List<Object>> buildBody3(DetailObjectVO object) {
        CalculateResultObjectVO calculateObject = object.getCalculateObject();
        CalculateResultVO result = calculateObject.getResult().get(0);

        List<List<Object>> body = new ArrayList<>();
        List<Object> objectList = new ArrayList<>();
        objectList.add(result.getCarCostRecovery());
        objectList.add(result.getFinancingCost());
        objectList.add(result.getInternalRate());
        objectList.add(result.getVatAndAdditional());
        objectList.add(result.getIncomeTax());
        objectList.add(result.getNetProfit());
        objectList.add(result.getSalvageValue());
        body.add(objectList);
        return body;
    }

    public List<List<String>> buildHeader4() {
        List<List<String>> header = new ArrayList<>();
        header.add(Collections.singletonList("第一年"));
        header.add(Collections.singletonList("第二年"));
        header.add(Collections.singletonList("第三年"));
        header.add(Collections.singletonList("第四年"));
        header.add(Collections.singletonList("第五年"));
        header.add(Collections.singletonList("第六年"));
        header.add(Collections.singletonList("第七年"));
        header.add(Collections.singletonList("第八年"));
        header.add(Collections.singletonList("合计"));
        return header;
    }
    //租金收入
    public List<List<Object>> buildBody4(DetailObjectVO object) {
        CalculateResultObjectVO calculateObject = object.getCalculateObject();
        FinanceItemVO rentalIncome = calculateObject.getRentalIncome().get(0);

        List<List<Object>> body = new ArrayList<>();
        List<Object> objectList = new ArrayList<>();
        objectList.add(rentalIncome.getOneYear());
        objectList.add(rentalIncome.getTwoYear());
        objectList.add(rentalIncome.getThreeYear());
        objectList.add(rentalIncome.getFourYear());
        objectList.add(rentalIncome.getFiveYear());
        objectList.add(rentalIncome.getSixYear());
        objectList.add(rentalIncome.getSevenYear());
        objectList.add(rentalIncome.getEightYear());
        objectList.add(rentalIncome.getTotal());
        body.add(objectList);
        return body;
    }


    public List<List<String>> buildHeader5() {
        List<List<String>> header = new ArrayList<>();
        header.add(Collections.singletonList("项目"));
        header.add(Collections.singletonList("第一年"));
        header.add(Collections.singletonList("第二年"));
        header.add(Collections.singletonList("第三年"));
        header.add(Collections.singletonList("第四年"));
        header.add(Collections.singletonList("第五年"));
        header.add(Collections.singletonList("第六年"));
        header.add(Collections.singletonList("第七年"));
        header.add(Collections.singletonList("第八年"));
        header.add(Collections.singletonList("合计"));
        return header;
    }
    //管理费用
    public List<List<Object>> buildBody5(DetailObjectVO object) {
        CalculateResultObjectVO calculateObject = object.getCalculateObject();
        List<FinanceItemVO> manageCostList = calculateObject.getManageCostList();
        List<List<Object>> body = new ArrayList<>();
        for(FinanceItemVO vo : manageCostList){
            List<Object> objectList = new ArrayList<>();
            objectList.add(vo.getItemName());
            objectList.add(vo.getOneYear());
            objectList.add(vo.getTwoYear());
            objectList.add(vo.getThreeYear());
            objectList.add(vo.getFourYear());
            objectList.add(vo.getFiveYear());
            objectList.add(vo.getSixYear());
            objectList.add(vo.getSevenYear());
            objectList.add(vo.getEightYear());
            objectList.add(vo.getTotal());
            body.add(objectList);
        }
        return body;
    }
    //收入与税金
    public List<List<Object>> buildBody6(DetailObjectVO object) {
        CalculateResultObjectVO calculateObject = object.getCalculateObject();
        FinanceItemVO incomeAndTax = calculateObject.getIncomeAndTax().get(0);
        List<List<Object>> body = new ArrayList<>();
        List<Object> objectList = new ArrayList<>();
        objectList.add(incomeAndTax.getItemName());
        objectList.add(incomeAndTax.getOneYear());
        objectList.add(incomeAndTax.getTwoYear());
        objectList.add(incomeAndTax.getThreeYear());
        objectList.add(incomeAndTax.getFourYear());
        objectList.add(incomeAndTax.getFiveYear());
        objectList.add(incomeAndTax.getSixYear());
        objectList.add(incomeAndTax.getSevenYear());
        objectList.add(incomeAndTax.getEightYear());
        objectList.add(incomeAndTax.getTotal());
        body.add(objectList);
        return body;
    }
    //成本与利润
    public List<List<Object>> buildBody7(DetailObjectVO object) {
        CalculateResultObjectVO calculateObject = object.getCalculateObject();
        List<FinanceItemVO> costAndProfitList = calculateObject.getCostAndProfitList();
        List<List<Object>> body = new ArrayList<>();
        for(FinanceItemVO vo : costAndProfitList){
            List<Object> objectList = new ArrayList<>();
            objectList.add(vo.getItemName());
            objectList.add(vo.getOneYear());
            objectList.add(vo.getTwoYear());
            objectList.add(vo.getThreeYear());
            objectList.add(vo.getFourYear());
            objectList.add(vo.getFiveYear());
            objectList.add(vo.getSixYear());
            objectList.add(vo.getSevenYear());
            objectList.add(vo.getEightYear());
            objectList.add(vo.getTotal());
            body.add(objectList);
        }
        return body;
    }
}
