package com.ffii.lioner.modules.common.service;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import com.ffii.lioner.modules.lioner.reportDao.AppreciationCaseReportDao;
import com.ffii.lioner.modules.lioner.reportDao.AppreciationChartDataDao;
import com.ffii.core.utils.NumberUtils;
import com.ffii.core.utils.RomanConverter;

import freemarker.template.Configuration;
import freemarker.template.Template;
import io.micrometer.common.util.StringUtils;

@Service
public class WordReportService {

    private static final String XML_TEST_TEMPLATE_PATH = "templates/report/Report 1 - Appreciations Case (Sample) - test.ftl";
    private static final String APPRECIATION_SUMMARY_TEMPLATE_PATH = "templates/report/Report 2 - Annex III – Summary of Appreciation Cases.ftl";
    private static final String[] chartColors = new String[] { "7FC817", "FF4F90", "FFD453", "FFF2CB", "41D3F3",
            "795AEE", "FFF547", "F9CB27", "EA871E", "FC001D", "4A2E95", "C8CBCD" };

    public byte[] generateTestXMLFile() throws IOException {
        ClassPathResource resource = new ClassPathResource(XML_TEST_TEMPLATE_PATH);
        InputStream templateInputStream = resource.getInputStream();

        try {
            // Load the FTL template
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
            cfg.setClassForTemplateLoading(WordReportService.class, "/");
            Template template = cfg.getTemplate(XML_TEST_TEMPLATE_PATH);

            // Create a data model
            Map<String, Object> dataModel = new HashMap<>();
            dataModel.put("reportDate", "June 2023");
            dataModel.put("monthTotal", String.format("%s (%d)", NumberUtils.convertToWord(14), 14));

            List<Map<String, Object>> catBreakDowns = new ArrayList<>();
            catBreakDowns.add(Map.of("catTotal", String.format("%s (%d)", NumberUtils.convertToWord(6), 6), "catName",
                    "project"));
            catBreakDowns.add(Map.of("catTotal", String.format("%s (%d)", NumberUtils.convertToWord(4), 4), "catName",
                    "maintenance"));
            catBreakDowns.add(
                    Map.of("catTotal", String.format("%s (%d)", NumberUtils.convertToWord(4), 4), "catName", "AA&I"));

            dataModel.put("catBreakDowns", catBreakDowns);

            dataModel.put("compareStr1", "more than");
            dataModel.put("compareStr2", "by five");

            dataModel.put("finYear", "2023/24");
            dataModel.put("yearTotal", 50);

            LinkedHashMap<String, Object> sbuYearTotal = new LinkedHashMap<>();
            sbuYearTotal.put("BTSD", 1);
            sbuYearTotal.put("CSD", 2);
            sbuYearTotal.put("GESD", 3);
            sbuYearTotal.put("HSD", 4);
            sbuYearTotal.put("MunSD", 5);
            sbuYearTotal.put("SVSD", 6);
            sbuYearTotal.put("DTD", 7);

            dataModel.put("sbuYearTotal", sbuYearTotal);

            int idx = 0;

            List<Map<String, Object>> series = new ArrayList<>();
            List<String> sbuList = Arrays.asList("BTSD", "CSD", "GESD", "HSD", "MunSD", "SVSD", "DTD");

            for (String sbu : sbuList) {
                Map<String, Object> serie = new HashMap<>();
                serie.put("serieName", sbu);
                serie.put("color", chartColors[idx % (chartColors.length - 1)]);
                serie.put("data",
                        Arrays.asList((int) (Math.random() * 1), (int) (Math.random() * 2), (int) (Math.random() * 3),
                                (int) (Math.random() * 4), (int) (Math.random() * 5), (int) (Math.random() * 6),
                                (int) (Math.random() * 7), (int) (Math.random() * 8), (int) (Math.random() * 9),
                                (int) (Math.random() * 10), (int) (Math.random() * 11), (int) (Math.random() * 12)));
                series.add(serie);

                idx++;
            }

            dataModel.put("series", series);

            dataModel.put("lnReceiptDateRange", "17 Jul 2023 – 31 Jul 2023");

            List<Map<String, Object>> aprRecords = new ArrayList<>();

            aprRecords.add(Map.of("sbu", "BTSD", "receiptDate", "17 Jul 2023", "description",
                    "An appreciation received on 28 July 2023 via 1823 from a citizen expressing appreciation to EMSD colleagues for their prompt action to rectify damaged traffic signal equipment located at Chatham Road North, Hung Hom.",
                    "clientReplyDate", "03 Jul 2023", "staffReplyDate", "04 Jul 2023", "numOfStaff", 4, "clientDeptOrg",
                    "Transport Department"));

            aprRecords.add(Map.of("sbu", "BTSD", "receiptDate", "22 Jul 2023", "description",
                    "Mr. Patrick K P CHENG, Chief Engineer/Traffic Survey & Support of TD, expressed the appreciation to BTSD’s colleagues for all the efforts and continuous support in commissioning of Journey Time Indicators (JTIs) to facilitate the opening of Tseung Kwan O – Lam Tin Tunnel (TKO-LTT) within very tight schedule.",
                    "clientReplyDate", "03 Jul 2023", "staffReplyDate", "04 Jul 2023", "numOfStaff", 7, "clientDeptOrg",
                    "Transport Department"));

            dataModel.put("aprRecords", aprRecords);

            /*
             * dataModel.put("reportTitle", "New Title");
             * 
             * List<String> headers = Arrays.asList("Header 0", "Header 1", "Header 2",
             * "Header 3");
             * dataModel.put("headers", headers);
             * 
             * List<String> rows1 = Arrays.asList("R1-1", "R1-2", "R1-3", "R1-4");
             * dataModel.put("rows1", rows1);
             * 
             * List<String> rows2 = Arrays.asList("R2-1", "R2-2", "R2-3", "R2-4");
             * dataModel.put("rows2", rows2);
             * 
             * Map<String, Object> chartData = new HashMap<>();
             * 
             * List<String> categories = Arrays.asList("Category 1", "Category 2",
             * "Category 3", "Category 4",
             * "Category 5");
             * chartData.put("categories", categories);
             * 
             * LinkedHashMap<String, Object> series = new LinkedHashMap<>();
             * 
             * List<Double> series1 = Arrays.asList(4.33, 2.55, 3.55, 4.55, 14.0);
             * Map<String, Object> serie1 = new HashMap<>();
             * serie1.put("col", "B");
             * serie1.put("data", series1);
             * serie1.put("size", 5);
             * series.put("Series 1", serie1);
             * 
             * List<Double> series2 = Arrays.asList(44.33, 22.55, 33.55, 44.55, 13.0);
             * Map<String, Object> serie2 = new HashMap<>();
             * serie2.put("col", "C");
             * serie2.put("data", series2);
             * serie2.put("size", 5);
             * series.put("Series 2", serie2);
             * 
             * List<Double> series3 = Arrays.asList(4.333, 2.555, 3.555, 4.555, 12.0);
             * Map<String, Object> serie3 = new HashMap<>();
             * serie3.put("col", "D");
             * serie3.put("data", series3);
             * serie3.put("size", 5);
             * series.put("Series 3", serie3);
             * 
             * chartData.put("series", series);
             * 
             * dataModel.put("chartData", chartData);
             */

            // Render the template with the data model
            StringWriter writer = new StringWriter();
            template.process(dataModel, writer);
            String output = writer.toString();

            byte[] byteArray = output.getBytes();

            return byteArray;

        } catch (Exception e) {
            e.printStackTrace();
            return null; // or handle the exception according to your requirements
        } finally {
            templateInputStream.close();
        }
    }

    public byte[] generateAppreciationCasesXMLFile(AppreciationCaseReportDao reportDao) throws IOException {
        try {
            // Load the FTL template
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
            cfg.setClassForTemplateLoading(WordReportService.class, "/");
            Template template = cfg.getTemplate(XML_TEST_TEMPLATE_PATH);

            // Create a data model
            Map<String, Object> dataModel = new HashMap<>();
            dataModel.put("reportDate", reportDao.getFormattedDateFrom());
            dataModel.put("monthTotal", String.format("%s (%d)", NumberUtils.convertToWord(reportDao.getCount().intValue()), reportDao.getCount().intValue()));

            dataModel.put("catBreakDowns", reportDao.getCatBreakDowns());

            dataModel.put("compareStr1", reportDao.getCompareStr1());
            dataModel.put("compareStr2", reportDao.getCompareStr2());

            dataModel.put("finYear", reportDao.getFinYear());
            dataModel.put("yearTotal", reportDao.getYearlyCount());

            LinkedHashMap<String, Object> sbuYearTotal = new LinkedHashMap<>();
            for (Map<String,Object> record : reportDao.getYearlyRecordCount()) {
            sbuYearTotal.put(
                (String) record.get("name"), 
                (Long) record.get("count")
                );
            }

            dataModel.put("sbuYearTotal", sbuYearTotal);

            int idx = 0;

            List<Map<String, Object>> series = new ArrayList<>();

            for (AppreciationChartDataDao record : reportDao.getChartList()) {
                Map<String, Object> serie = new HashMap<>();
                serie.put("serieName", record.getSbuName());
                serie.put("color", chartColors[idx % (chartColors.length - 1)]);
                serie.put("data",record.getRecordByMonth());
            
                series.add(serie);

                idx++;
            }

            dataModel.put("series", series);

            dataModel.put("lnReceiptDateRange", reportDao.getLnReceiptDateRange());

            List<Map<String, Object>> aprRecords = new ArrayList<>();

            final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd MMM YYYY");

            for (Map<String,Object> record : reportDao.getAppreciationRecordDetail()) {
                aprRecords.add(Map.of(
                    "sbu", record.get("sbuNames") == null ? "" : record.get("sbuNames"), 
                    "receiptDate", record.get("receiptDate") == null ? "" : ((LocalDateTime)record.get("receiptDate")).format(dateFormat), 
                    "description", record.get("description") == null ? "" : record.get("description"),
                    "clientReplyDate", record.get("clientReplyDate") == null ? "" : ((LocalDateTime)record.get("clientReplyDate")).format(dateFormat), 
                    "staffReplyDate", record.get("staffReplyDate") == null ? "" : ((LocalDateTime)record.get("staffReplyDate")).format(dateFormat),
                    "numOfStaff", record.get("noOfStaff") == null ? "" : record.get("noOfStaff").toString(), 
                    "clientDeptOrg", !StringUtils.isBlank((String)record.get("clientDepartment")) ? record.get("clientDepartment") : record.get("clientOrganization")
                ));
    
            }

            dataModel.put("aprRecords", aprRecords);

            // Render the template with the data model
            StringWriter writer = new StringWriter();
            template.process(dataModel, writer);
            String output = writer.toString();

            byte[] byteArray = output.getBytes();

            return byteArray;

        } catch (Exception e) {
            e.printStackTrace();
            return null; // or handle the exception according to your requirements
        }
    }

    public byte[] generateAppreciationSummaryXMLFile(String reportHeading, List<Map<String,Object>> reportRecord) throws IOException {
        ClassPathResource resource = new ClassPathResource(APPRECIATION_SUMMARY_TEMPLATE_PATH);
        InputStream templateInputStream = resource.getInputStream();

        try {
            // Load the FTL template
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
            cfg.setClassForTemplateLoading(WordReportService.class, "/");
            Template template = cfg.getTemplate(APPRECIATION_SUMMARY_TEMPLATE_PATH);

            // Create a data model
            Map<String, Object> dataModel = new HashMap<>();
            dataModel.put("reportDate", reportHeading);

            List<Map<String, Object>> aprRecords = new ArrayList<>();

            Integer count = 1;
            for (Map<String,Object> record : reportRecord) {
                aprRecords.add(Map.of(
                    "index", "(" + RomanConverter.convertToRoman(count, false) + ")",
                    "description", record.get("description"),
                    "category", record.get("category")
                ));
                count++;
            }

            dataModel.put("aprRecords", aprRecords);

            // Render the template with the data model
            StringWriter writer = new StringWriter();
            template.process(dataModel, writer);
            String output = writer.toString();

            byte[] byteArray = output.getBytes();

            return byteArray;

        } catch (Exception e) {
            e.printStackTrace();
            return null; // or handle the exception according to your requirements
        } finally {
            templateInputStream.close();
        }
    }


}
