package com.ecep.contract.task;

import static com.ecep.contract.util.ExcelUtils.setCellValue;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.stream.Collectors;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
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.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils;

import com.ecep.contract.Message;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.controller.contract.ContractVerifyWindowController;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.Employee;
import com.ecep.contract.service.ContractService;
import com.ecep.contract.service.EmployeeService;

import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * 导出验证结果为Excel文件
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class ContractVerifyResultExportAsExcelFileTasker extends Tasker<Object> {

    File destFile;

    List<ContractVerifyWindowController.Model> models;

    EmployeeService employeeService;
    ContractService contractService;

    public EmployeeService getEmployeeService() {
        if (employeeService == null) {
            employeeService = SpringApp.getBean(EmployeeService.class);
        }
        return employeeService;
    }

    public ContractService getContractService() {
        if (contractService == null) {
            contractService = SpringApp.getBean(ContractService.class);
        }
        return contractService;
    }

    @Override
    protected Object execute(MessageHolder holder) throws Exception {
        holder.debug("共有信息 " + models.size() + " 条");

        Employee unnamed = new Employee();
        unnamed.setName("未命名");

        // 按员工分组
        Map<Employee, List<ContractVerifyWindowController.Model>> listMap = models.stream()
                .collect(Collectors.groupingBy(model -> {
                    Employee employee = model.getEmployee().get();
                    if (employee == null) {
                        employee = unnamed;
                    }
                    return employee;
                }));

        holder.debug("按员工分为 " + listMap.size() + " 组");
        updateProgress(0, listMap.size());

        try (Workbook wb = new XSSFWorkbook()) {
            String[] headers = { "合同编号", "合同名称", "验证结果", "路径" };
            int[] columnWidths = { 14, 25, 50, 20 };

            // 创建样式：启用自动换行
            CellStyle wrapStyle = wb.createCellStyle();
            wrapStyle.setWrapText(true); // 关键设置：自动换行

            AtomicInteger counter = new AtomicInteger();
            for (Map.Entry<Employee, List<ContractVerifyWindowController.Model>> entry : listMap.entrySet()) {
                Employee employee = entry.getKey();
                List<ContractVerifyWindowController.Model> list = entry.getValue();

                //
                employee = getEmployeeService().findById(employee.getId());
                holder.info("- " + employee.getName());
                // 创建工作表
                String sheetName = employee.getName();
                if (!StringUtils.hasText(sheetName)) {
                    sheetName = "未命名";
                }
                Sheet sheet = wb.createSheet(sheetName);
                // 创建表头行
                Row headerRow = sheet.createRow(0);

                // 创建表头单元格并设置值
                for (int i = 0; i < headers.length; i++) {
                    Cell cell = headerRow.createCell(i);
                    cell.setCellValue(headers[i]);

                    sheet.setColumnWidth(i, columnWidths[i] * 256);
                }

                list.sort(Comparator.comparing(o -> o.getCode().get()));

                for (int i = 0; i < list.size(); i++) {
                    try {
                        ContractVerifyWindowController.Model model = list.get(i);
                        Contract contract = getContractService().findByCode(model.getCode().get());
                        Row row = sheet.createRow(i + 1);
                        setCellValue(sheet, row.getRowNum(), 0, model.getCode().get());
                        setCellValue(sheet, row.getRowNum(), 1, model.getName().get());
                        Map<String, List<ContractVerifyWindowController.MessageExt>> messages = model.getMessages()
                                .get()
                                .stream()
                                .filter(v -> v.getLevel().intValue() > Level.INFO.intValue())
                                .collect(Collectors.groupingBy(v -> {
                                    if (v.getPrefix() == null) {
                                        return "";
                                    }
                                    return v.getPrefix();
                                }));

                        setCellValue(sheet, row.getRowNum(), 2, messages.entrySet().stream()
                                .sorted(Comparator.comparing(Map.Entry::getKey))
                                .map((e) -> {
                                    return e.getKey() + e.getValue().stream()
                                            .map(Message::getMessage)
                                            .collect(Collectors.joining(", "));
                                }).collect(Collectors.joining("\n"))).setCellStyle(wrapStyle);

                        if (contract != null) {
                            setCellValue(sheet, row.getRowNum(), 3, contract.getPath());
                        }
                    } catch (Exception e) {
                        holder.error(e.getMessage());
                    }
                }
                sheet.autoSizeColumn(2);
                updateProgress(counter.incrementAndGet(), listMap.size());
            }

            holder.debug("写入文件：" + destFile.getAbsolutePath());
            try (OutputStream fileOut = new FileOutputStream(destFile)) {
                wb.write(fileOut);
            }
            updateProgress(1, 1);
        }
        return null;
    }
}
