package com.ecep.contract.controller.project.cost;

import static com.ecep.contract.util.ExcelUtils.copyStyle;
import static com.ecep.contract.util.ExcelUtils.getCell;
import static com.ecep.contract.util.ExcelUtils.getCellValue;
import static com.ecep.contract.util.ExcelUtils.getRow;
import static com.ecep.contract.util.ExcelUtils.mergedCells;
import static com.ecep.contract.util.ExcelUtils.setCellValue;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDate;
import java.util.List;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.PageMargin;
import org.apache.poi.ss.usermodel.PrintSetup;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.ss.util.CellRangeAddress;
import com.ecep.contract.util.ProxyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.ecep.contract.MessageHolder;
import com.ecep.contract.constant.ContractConstant;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.ProductType;
import com.ecep.contract.model.Project;
import com.ecep.contract.model.ProjectCost;
import com.ecep.contract.model.ProjectCostItem;
import com.ecep.contract.model.ProjectIndustry;
import com.ecep.contract.model.ProjectSaleType;
import com.ecep.contract.model.ProjectType;
import com.ecep.contract.service.ProductTypeService;
import com.ecep.contract.service.ProjectCostItemService;
import com.ecep.contract.service.ProjectCostService;
import com.ecep.contract.service.ProjectIndustryService;
import com.ecep.contract.service.ProjectService;
import com.ecep.contract.service.ProjectTypeService;
import com.ecep.contract.service.SaleTypeService;
import com.ecep.contract.task.Tasker;

import lombok.Setter;

public class ProjectCostExportExcelTasker extends Tasker<Object> {
    private static final Logger logger = LoggerFactory.getLogger(ProjectCostExportExcelTasker.class);
    private String name = "成本核算审批表";
    @Setter
    private ProjectCost cost;
    @Setter
    private ProjectService projectService;
    @Setter
    private ProjectCostService costService;
    @Setter
    private ProjectCostItemService itemService;

    ProjectService getProjectService() {
        if (projectService == null) {
            projectService = getBean(ProjectService.class);
        }
        return projectService;
    }

    ProjectCostService getCostService() {
        if (costService == null) {
            costService = getBean(ProjectCostService.class);
        }
        return costService;
    }

    ProjectCostItemService getItemService() {
        if (itemService == null) {
            itemService = getBean(ProjectCostItemService.class);
        }
        return itemService;
    }

    @Override
    protected Object execute(MessageHolder holder) throws Exception {
        updateTitle("根据模板导出" + name);

        // \\10.84.209.8\规章制度\ISO9000\01-最新发布版\4_JL_记录文件\ECEP-JL-XS-01-E_设备销售成本核算审批表.xlsx
        String path = getConfService().getString(ContractConstant.KEY_CUSTOMER_COST_TEMPLATE);
        if (!StringUtils.hasText(path)) {
            holder.error(name + "模板文件未设置，请先设置" + name + "模板文件");
            return null;
        }
        File template = new File(path);
        if (!template.exists()) {
            holder.warn(name + "模板文件 " + template.getAbsolutePath() + " 不存在，请检查");
            return null;
        }

        Project project = cost.getProject();
        if (!ProxyUtils.isInitialized(project)) {
            project = getProjectService().findById(project.getId());
            cost.setProject(project);
        }
        File dir = getProjectService().searchPath(project);
        LocalDate thatDay = LocalDate.now();
        if (cost.getApplyTime() != null) {
            thatDay = cost.getApplyTime().toLocalDate();
        }
        String filename = name + "_v" + cost.getVersion() + "_" + thatDay;
        String extension = StringUtils.getFilenameExtension(path);
        File destFile = new File(dir, filename + "." + extension);
        int count = 0;
        while (destFile.exists()) {
            holder.warn(destFile.getName() + " 已存在");
            destFile = new File(dir, filename + "_" + (++count) + "." + extension);
        }

        try (
                InputStream inp = new FileInputStream(template);
                Workbook wb = WorkbookFactory.create(inp)) {
            updateProjectCost(wb, destFile, holder);
            holder.info(name + "保存到" + destFile.getName() + "!");
        } catch (Exception e) {
            holder.error(e.getMessage());
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    Sheet findSheetByNameContains(Workbook wb, String sheetName) {
        for (int i = 0; i < wb.getNumberOfSheets(); i++) {
            Sheet s = wb.getSheetAt(i);
            if (s.getSheetName().contains(sheetName)) {
                return s;
            }
        }
        return null;
    }

    private void updateProjectCost(Workbook wb, File destFile, MessageHolder holder) throws IOException {

        Sheet sheet = findSheetByNameContains(wb, name);
        if (sheet == null) {
            holder.error("找不到" + name + "表");
            return;
        }
        holder.info("模板版本：" + getCellValue(sheet, "L1"));

        updateProjectCost(sheet, holder);
        // 输出到文件
        try (OutputStream fileOut = new FileOutputStream(destFile)) {
            wb.write(fileOut);
        } catch (FileNotFoundException e) {
            holder.error("写时发生文件错误，请检查文件是否被打开中, " + e.getMessage());
            logger.error(e.getMessage(), e);
        }
    }

    private void updateProjectCost(Sheet sheet, MessageHolder holder) {
        updateTitle("更新 " + sheet.getSheetName() + " Sheet");
        Project project = cost.getProject();

        setCellValue(sheet, "C5", project.getName());

        Company customer = project.getCustomer();
        if (customer != null) {
            if (!ProxyUtils.isInitialized(customer)) {
                customer = getCompanyService().findById(customer.getId());
                project.setCustomer(customer);
            }
            setCellValue(sheet, "C6", customer.getName());
        } else {
            setCellValue(sheet, "C6", "-");
        }
        setCellValue(sheet, "C7", project.getAddress());

        ProjectType projectType = project.getProjectType();
        if (projectType != null) {
            if (!ProxyUtils.isInitialized(projectType)) {
                projectType = getBean(ProjectTypeService.class).findById(projectType.getId());
                project.setProjectType(projectType);
            }
            setCellValue(sheet, "I5", projectType.getName());
        } else {
            setCellValue(sheet, "I5", "");
        }

        ProductType productType = project.getProductType();
        if (productType != null) {
            if (!ProxyUtils.isInitialized(productType)) {
                productType = getBean(ProductTypeService.class).findById(productType.getId());
                project.setProductType(productType);
            }
            setCellValue(sheet, "I6", productType.getName());
        } else {
            setCellValue(sheet, "I6", "");
        }

        if (cost.getApplyTime() != null) {
            setCellValue(sheet, "I7", cost.getApplyTime().toLocalDate());
        } else {
            setCellValue(sheet, "I7", project.getCreated());
        }

        ProjectSaleType saleType = project.getSaleType();
        if (saleType != null) {
            if (!ProxyUtils.isInitialized(saleType)) {
                saleType = getBean(SaleTypeService.class).findById(saleType.getId());
                project.setSaleType(saleType);
            }
            setCellValue(sheet, "M5", saleType.getName());
        } else {
            setCellValue(sheet, "M5", "");
        }

        ProjectIndustry industry = project.getIndustry();
        if (industry != null) {
            if (!ProxyUtils.isInitialized(industry)) {
                industry = getBean(ProjectIndustryService.class).findById(industry.getId());
                project.setIndustry(industry);
            }
            setCellValue(sheet, "M6", industry.getName());
        } else {
            setCellValue(sheet, "M6", "");
        }

        Employee applicant = project.getApplicant();
        if (applicant != null) {
            if (!ProxyUtils.isInitialized(applicant)) {
                applicant = getEmployeeService().findById(applicant.getId());
                project.setApplicant(applicant);
            }
            setCellValue(sheet, "M7", applicant.getName());
        } else {
            setCellValue(sheet, "M7", "");
        }

        setCellValue(sheet, "D39", cost.getStampTax() / 100);
        setCellValue(sheet, "D40", cost.getTaxAndSurcharges() / 100);

        List<ProjectCostItem> items = getItemService().findByCost(cost);
        if (items.size() > 27) {
            holder.warn("读取到 " + items.size() + " 行, 超出最大行数27行，已截断导出到附加表中");
            int row = 10;
            setCellValue(sheet, row, 0, "详见附表");
            setCellValue(sheet, row, 2, "");
            setCellValue(sheet, row, 3, 1);
            // 含税售价
            setCellValue(sheet, row, 4,
                    items.stream().mapToDouble(
                            v -> v.getInQuantity() * v.getInExclusiveTaxPrice() * (100 + v.getInTaxRate()) / 100)
                            .sum());
            Cell cellTax = getCell(sheet, row, 6, false);
            if (cellTax != null) {
                cellTax.setBlank();
            }
            // setCellValue(sheet, row, 6, 0);
            setCellValue(sheet, row, 7,
                    items.stream().mapToDouble(v -> v.getInQuantity() * v.getInExclusiveTaxPrice()).sum());
            // 含税进价
            setCellValue(sheet, row, 8,
                    items.stream().mapToDouble(
                            v -> v.getOutQuantity() * v.getOutExclusiveTaxPrice() * (100 + v.getOutTaxRate()) / 100)
                            .sum());
            setCellValue(sheet, row, 10, 0);
            setCellValue(sheet, row, 11,
                    items.stream().mapToDouble(v -> v.getOutQuantity() * v.getOutExclusiveTaxPrice()).sum());

            writeItem2Detail(sheet, items, holder);
            return;
        }
        for (int i = 0; i < items.size(); i++) {
            ProjectCostItem item = items.get(i);
            int row = 10 + i;
            drawRow(sheet, row, item);
        }
    }

    private void writeItem2Detail(Sheet sheet, List<ProjectCostItem> items, MessageHolder holder) {
        Sheet detailSheet = findSheetByNameContains(sheet.getWorkbook(), "附加表");
        if (detailSheet == null) {
            detailSheet = sheet.getWorkbook().createSheet("附加表");
            holder.info("创建 附加表 Sheet");

            mergedCells(detailSheet, "A1:N1");
            setCellValue(detailSheet, "A1", "成本详表");
            copyStyle(sheet, "A8", detailSheet, "A1");

            detailSheet.getRow(0).setHeight((short) (30 * 20));

            mergedCells(detailSheet, "A2:B2");
            setCellValue(detailSheet, "A2", "");
            copyStyle(sheet, "A9", detailSheet, "A2");

            mergedCells(detailSheet, "C2:G2");
            setCellValue(detailSheet, "C2", "出项");
            copyStyle(sheet, "A9", detailSheet, "C2");

            mergedCells(detailSheet, "H2:L2");
            setCellValue(detailSheet, "H2", "进项");
            copyStyle(sheet, "I9", detailSheet, "H2");

            mergedCells(detailSheet, "M2:N2");
            setCellValue(detailSheet, "M2", "");
            copyStyle(sheet, "I9", detailSheet, "M2");

            setCellValue(detailSheet, "A3", "设备名称");
            detailSheet.setColumnWidth(0, 30 * 256);
            copyStyle(sheet, "A10", detailSheet, "A3");

            setCellValue(detailSheet, "B3", "设备型号");
            detailSheet.setColumnWidth(1, 30 * 256);
            copyStyle(sheet, "C10", detailSheet, "B3");

            setCellValue(detailSheet, "C3", "数量");
            detailSheet.setColumnWidth(2, 8 * 256);
            copyStyle(sheet, "D10", detailSheet, "C3");

            setCellValue(detailSheet, "D3", "单价（含税元）");
            detailSheet.setColumnWidth(3, 13 * 256);
            copyStyle(sheet, "E10", detailSheet, "D3");

            setCellValue(detailSheet, "E3", "销售价格（含税元）");
            detailSheet.setColumnWidth(4, 13 * 256);
            copyStyle(sheet, "F10", detailSheet, "E3");

            setCellValue(detailSheet, "F3", "税率");
            copyStyle(sheet, "G10", detailSheet, "F3");

            setCellValue(detailSheet, "G3", "未税金额（元）");
            detailSheet.setColumnWidth(6, 13 * 256);
            copyStyle(sheet, "H10", detailSheet, "G3");

            setCellValue(detailSheet, "H3", "数量");
            detailSheet.setColumnWidth(7, 8 * 256);
            copyStyle(sheet, "D10", detailSheet, "H3");

            setCellValue(detailSheet, "I3", "单价（含税元）");
            detailSheet.setColumnWidth(8, 13 * 256);
            copyStyle(sheet, "I10", detailSheet, "I3");

            setCellValue(detailSheet, "J3", "合价（含税元）");
            detailSheet.setColumnWidth(9, 13 * 256);
            copyStyle(sheet, "J10", detailSheet, "J3");

            setCellValue(detailSheet, "K3", "税率");
            copyStyle(sheet, "K10", detailSheet, "K3");

            setCellValue(detailSheet, "L3", "未税金额（元）");
            detailSheet.setColumnWidth(11, 13 * 256);
            copyStyle(sheet, "L10", detailSheet, "L3");

            setCellValue(detailSheet, "M3", "毛利GM");
            detailSheet.setColumnWidth(12, 13 * 256);
            copyStyle(sheet, "M10", detailSheet, "M3");

            setCellValue(detailSheet, "N3", "毛利率GM%");
            detailSheet.setColumnWidth(13, 12 * 256);
            copyStyle(sheet, "N10", detailSheet, "N3");
        }

        for (int i = 0; i < items.size(); i++) {
            ProjectCostItem item = items.get(i);
            int rowIndex = 3 + i;
            Row theRow = getRow(detailSheet, rowIndex, true);
            if (theRow == null) {
                holder.error("Sheet:" + detailSheet.getSheetName() + " 无法访问/创建第" + rowIndex + "行");
                continue;
            }
            drawDetailRow(theRow, item);
            copyStyle(sheet, "A11", detailSheet, "A" + (rowIndex + 1));
            copyStyle(sheet, "C11", detailSheet, "B" + (rowIndex + 1));
            copyStyle(sheet, "D11", detailSheet, "C" + (rowIndex + 1));
            copyStyle(sheet, "E11", detailSheet, "D" + (rowIndex + 1));
            copyStyle(sheet, "F11", detailSheet, "E" + (rowIndex + 1));
            copyStyle(sheet, "G11", detailSheet, "F" + (rowIndex + 1));
            copyStyle(sheet, "H11", detailSheet, "G" + (rowIndex + 1));
            copyStyle(sheet, "D11", detailSheet, "H" + (rowIndex + 1));
            copyStyle(sheet, "I11", detailSheet, "I" + (rowIndex + 1));
            copyStyle(sheet, "J11", detailSheet, "J" + (rowIndex + 1));
            copyStyle(sheet, "K11", detailSheet, "K" + (rowIndex + 1));
            copyStyle(sheet, "L11", detailSheet, "L" + (rowIndex + 1));
            copyStyle(sheet, "M11", detailSheet, "M" + (rowIndex + 1));
            copyStyle(sheet, "N11", detailSheet, "N" + (rowIndex + 1));
        }

        {
            Row theRow = getRow(detailSheet, items.size() + 3, true);
            Cell cell1 = setCellValue(theRow, 0, "合计");
            mergedCells(cell1, 0, 1);
            copyStyle(sheet, "A42", cell1);
            copyStyle(sheet, "A42", setCellValue(theRow, 1, ""));
            theRow.setHeight((short) (28 * 20));

            int rowIndex = theRow.getRowNum() - 1;
            Cell cell2 = getCell(theRow, 2, true);
            if (cell2 != null) {
                // =SUM(C4:C136)
                CellAddress c$136 = new CellAddress(rowIndex, 2);
                cell2.setCellFormula("SUM(C4:" + c$136 + ")");

                copyStyle(sheet, "D42", cell2);
            }

            copyStyle(sheet, "E42", setCellValue(theRow, 3, ""));

            // 销售金额合计
            Cell cell3 = getCell(theRow, 4, true);
            if (cell3 != null) {
                // =SUM(E4:E136)
                CellAddress e$136 = new CellAddress(rowIndex, 4);
                cell3.setCellFormula("SUM(E4:" + e$136 + ")");

                copyStyle(sheet, "F42", cell3);
            }

            copyStyle(sheet, "D42", setCellValue(theRow, 5, ""));

            // 未税销售金额合计
            Cell cell4 = getCell(theRow, 6, true);
            if (cell4 != null) {
                // =SUM(G4:G136)
                CellAddress g$136 = new CellAddress(rowIndex, 6);
                cell4.setCellFormula("SUM(G4:" + g$136 + ")");

                copyStyle(sheet, "H42", cell4);
            }

            // 采购数量合计
            Cell cell5 = getCell(theRow, 7, true);
            if (cell5 != null) {
                // =SUM(H4:H136)
                CellAddress h$036 = new CellAddress(rowIndex, 7);
                cell5.setCellFormula("SUM(H4:" + h$036 + ")");
                copyStyle(sheet, "D42", cell5);
            }

            copyStyle(sheet, "I42", setCellValue(theRow, 8, ""));

            // 采购金额合计
            Cell cell6 = getCell(theRow, 9, true);
            if (cell6 != null) {
                // =SUM(J4:J136)
                CellAddress j$036 = new CellAddress(rowIndex, 9);
                cell6.setCellFormula("SUM(J4:" + j$036 + ")");
                copyStyle(sheet, "J42", cell6);
            }

            copyStyle(sheet, "D42", setCellValue(theRow, 10, ""));

            // 未税采购金额合计
            Cell cell7 = getCell(theRow, 11, true);
            if (cell7 != null) {
                // =SUM(L4:L136)
                CellAddress l$036 = new CellAddress(rowIndex, 11);
                cell7.setCellFormula("SUM(L4:" + l$036 + ")");
                copyStyle(sheet, "L42", cell7);
            }

            // 毛利合计
            Cell cell8 = getCell(theRow, 12, true);
            if (cell8 != null) {
                // =SUM(M4:M136)
                CellAddress m$036 = new CellAddress(rowIndex, 12);
                cell8.setCellFormula("SUM(M4:" + m$036 + ")");
                copyStyle(sheet, "M42", cell8);
            }

            // 总毛利率
            Cell cell9 = getCell(theRow, 13, true);
            if (cell9 != null) {
                // =IF(G42=0,IF(L42=0,"","-100%"),M42/G42)
                CellAddress g$42 = new CellAddress(rowIndex, 6);
                CellAddress l$42 = new CellAddress(rowIndex, 11);
                CellAddress m$42 = new CellAddress(rowIndex, 12);
                cell9.setCellFormula("IF(" + g$42 + "=0,IF(" + l$42 + "=0,\"\",\"-100%\")," + m$42 + "/" + g$42 + ")");
                copyStyle(sheet, "N42", cell9);
            }

            detailSheet.setRepeatingRows(CellRangeAddress.valueOf("$1:$3"));
            detailSheet.getFooter().setCenter("第 &P 页, 共 &N 页");
            detailSheet.getFooter().setRight("&D &T");

            Workbook wb = sheet.getWorkbook();

            wb.setPrintArea(wb.getSheetIndex(detailSheet), "A1:N" + (theRow.getRowNum() + 1));
            PrintSetup printSetup = detailSheet.getPrintSetup();

            printSetup.setPaperSize(PrintSetup.A4_PAPERSIZE); // A4 纸
            printSetup.setLandscape(true); // 横向打印
            printSetup.setFitHeight((short) 0);
            printSetup.setFitWidth((short) 1); // 调整为 1 页宽

            detailSheet.setFitToPage(true);
            detailSheet.setHorizontallyCenter(true);
            detailSheet.setVerticallyCenter(false);

            // 设置页边距（单位：英寸）
            detailSheet.setMargin(PageMargin.LEFT, 1.8 / 2.54); // 将厘米转换为英寸
            detailSheet.setMargin(PageMargin.RIGHT, 1.8 / 2.54);
            detailSheet.setMargin(PageMargin.TOP, 1.9 / 2.54);
            detailSheet.setMargin(PageMargin.BOTTOM, 1.9 / 2.54);

        }
    }

    void drawRow(Sheet sheet, int row, ProjectCostItem item) {
        setCellValue(sheet, row, 0, item.getTitle());
        setCellValue(sheet, row, 2, item.getSpecification());
        setCellValue(sheet, row, 3, item.getInQuantity());
        // 含税销售价格
        setCellValue(sheet, row, 4, item.getInExclusiveTaxPrice() * (100 + item.getInTaxRate()) / 100);
        setCellValue(sheet, row, 6, item.getInTaxRate() / 100);
        setCellValue(sheet, row, 8, item.getOutExclusiveTaxPrice() * (100 + item.getOutTaxRate()) / 100);
        setCellValue(sheet, row, 10, item.getOutTaxRate() / 100);
    }

    void drawDetailRow(Row row, ProjectCostItem item) {

        setCellValue(row, 0, item.getTitle());
        setCellValue(row, 1, item.getSpecification());
        setCellValue(row, 2, item.getInQuantity());
        // 含税销售价格
        setCellValue(row, 3, item.getInExclusiveTaxPrice() * (100 + item.getInTaxRate()) / 100);
        //
        Cell cell = getCell(row, 4, true);
        if (cell != null) {
            // =D4*C4
            CellAddress d$4 = new CellAddress(row.getRowNum(), 3);
            CellAddress c$4 = new CellAddress(row.getRowNum(), 2);
            cell.setCellFormula(d$4 + "*" + c$4);
        }
        setCellValue(row, 5, item.getInTaxRate() / 100);
        Cell cell1 = getCell(row, 6, true);
        if (cell1 != null) {
            // =IF(E4="",0,E4/(1+F4))
            CellAddress e$4 = new CellAddress(row.getRowNum(), 4);
            CellAddress f$4 = new CellAddress(row.getRowNum(), 5);
            cell1.setCellFormula("IF(" + e$4 + "=\"\",0," + e$4 + "/(1+" + f$4 + "))");
        }

        setCellValue(row, 7, item.getOutQuantity());
        setCellValue(row, 8, item.getOutExclusiveTaxPrice() * (100 + item.getOutTaxRate()) / 100);
        Cell cell2 = getCell(row, 9, true);
        if (cell2 != null) {
            // =I4*H4
            CellAddress h$4 = new CellAddress(row.getRowNum(), 7);
            CellAddress i$4 = new CellAddress(row.getRowNum(), 8);
            cell2.setCellFormula(h$4 + "*" + i$4);
        }
        setCellValue(row, 10, item.getOutTaxRate() / 100);
        Cell cell3 = getCell(row, 11, true);
        if (cell3 != null) {
            // =IF(J4="",0,J4/(1+K4))
            CellAddress j$4 = new CellAddress(row.getRowNum(), 9);
            CellAddress k$4 = new CellAddress(row.getRowNum(), 10);
            cell3.setCellFormula("IF(" + j$4 + "=\"\",0," + j$4 + "/(1+" + k$4 + "))");
        }
        // 毛利GM
        Cell cell4 = getCell(row, 12, true);
        if (cell4 != null) {
            // =IF(G4=0,IF(L4=0,0,G4-L4),G4-L4)
            CellAddress g$4 = new CellAddress(row.getRowNum(), 6);
            CellAddress l$4 = new CellAddress(row.getRowNum(), 11);
            cell4.setCellFormula(
                    "IF(" + g$4 + "=0,IF(" + l$4 + "=0,0," + g$4 + "-" + l$4 + ")," + g$4 + "-" + l$4 + ")");
        }

        // 毛利率GM%
        Cell cell5 = getCell(row, 13, true);
        if (cell5 != null) {
            // =IF(G4=0,IF(M4=0,0,"-100%"),M4/G4)
            CellAddress g$4 = new CellAddress(row.getRowNum(), 6);
            CellAddress m$4 = new CellAddress(row.getRowNum(), 12);
            cell5.setCellFormula("IF(" + g$4 + "=0,IF(" + m$4 + "=0,0,\"-100%\")," + m$4 + "/" + g$4 + ")");
        }

    }

}
