package com.ffii.lioner.modules.lioner.web;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ffii.lioner.modules.lioner.req.CreateImportErrorReportReq;
import com.ffii.lioner.modules.lioner.service.AppreciationService;
import com.ffii.lioner.modules.lioner.service.FileRefService;
import com.ffii.lioner.modules.lioner.service.FileService;
import com.ffii.lioner.modules.common.service.ExcelReportService;
import com.ffii.lioner.modules.master.service.SBUDivisionService;
import com.ffii.core.exception.NotFoundException;
import com.ffii.core.response.RecordsRes;
import com.ffii.core.utils.CriteriaArgsBuilder;
import com.ffii.core.utils.Params;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;

@RestController
@RequestMapping("/appreciation")
public class AppreciationController{

    private final Log logger = LogFactory.getLog(getClass());
    private AppreciationService appreciationService;
	private FileRefService fileRefService;
	private FileService fileService;
	private ExcelReportService excelReportService;
	private SBUDivisionService sbuDivisionService;

	public AppreciationController(
		AppreciationService appreciationService,
		FileRefService fileRefService,
		FileService fileService,
		ExcelReportService excelReportService,
		SBUDivisionService sbuDivisionService
		) {
		this.appreciationService = appreciationService;
		this.fileRefService = fileRefService;
		this.fileService = fileService;
		this.excelReportService = excelReportService;
		this.sbuDivisionService = sbuDivisionService;
	}
    
    // @PostMapping("/save")
	// public IdRes saveOrUpdate(@RequestBody @Valid UpdateAppreciationReq req) {
	// 	return new IdRes(appreciationService.saveOrUpdate(req).getId());
	// }

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
	@PostMapping(value = "/save", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
	public Map<String, Object> saveOrUpdate(
        @RequestParam Long id,
        @RequestParam String sbuIds,
        @RequestParam LocalDate receiptDate ,
        @RequestParam String description ,
        @RequestParam(value = "clientDepartment", required = false) String clientDepartment ,
        @RequestParam(value = "clientOrganization", required = false) String clientOrganization ,
        @RequestParam(value = "clientFullname", required = false) String clientFullname ,
        @RequestParam(value = "clientPost", required = false) String clientPost ,
        @RequestParam(value = "venue", required = false) String venue ,
        @RequestParam(value = "clientReplyDate", required = false) LocalDate clientReplyDate ,
        @RequestParam(value = "staffReplyDate", required = false) LocalDate staffReplyDate ,
        @RequestParam(value = "noOfStaff", required = false) Long noOfStaff ,
        @RequestParam LocalDate lnReceiptDate ,
        @RequestParam Long aprCategoryId ,
        @RequestParam(value = "remarks", required = false)  String remarks,
        @RequestParam(value = "files", required = false) MultipartFile[] files) throws Exception {
            
			Map<String,Object> resultMap = appreciationService.saveOrUpdate(
				id, sbuIds, receiptDate, description, clientDepartment,
				clientOrganization, clientFullname, clientPost, venue, clientReplyDate,
				staffReplyDate, noOfStaff, lnReceiptDate, aprCategoryId, remarks,
				files
			);

			return Map.of(Params.DATA, resultMap);
	}

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
	@PostMapping(value = "/massImport", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
	public Map<String, Object> massImport(
        @RequestParam(value = "files", required = false) MultipartFile[] files) throws Exception {
			Map<String,Object> resultMap = appreciationService.massImport(files);
			return Map.of(Params.DATA, resultMap);
	}

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
	@DeleteMapping("/{id}")
	@ResponseStatus(HttpStatus.NO_CONTENT)
	public void delete(@PathVariable Long id) {
		appreciationService.markDeleteWithAuditLog(appreciationService.find(id).get());
	}

	@GetMapping("/{id}")
	public Map<String, Object> get(@PathVariable Long id) {
		return Map.of(
				Params.DATA, appreciationService.find(id).orElseThrow(NotFoundException::new)
			);
	}

	@GetMapping("/yearCombo")
	public Map<String, Object> getYearCombo() {
		return Map.of(
				Params.RECORDS, appreciationService.getAppreciationYearCombo()
			);
	}
	
    @GetMapping
	public RecordsRes<Map<String, Object>> list(HttpServletRequest request) throws ServletRequestBindingException {
		System.out.println(request);
		return new RecordsRes<>(appreciationService.list(
				CriteriaArgsBuilder.withRequest(request)
						.addInteger("id")
						.addString("sbuIds")
						.addIntegerList("categoryIds")
						.addStringLike("clientDepOrOrg")
						.addStringLike("clientName")
						.addDate("receiptDateFrom")
                		.addDateTo("receiptDateTo")
						.addDate("lnReceiptDateFrom")
                		.addDateTo("lnReceiptDateTo")
						.addDate("clientReplyDateFrom")
                		.addDateTo("clientReplyDateTo")
						.addDate("staffReplyDateFrom")
                		.addDateTo("staffReplyDateTo")
						.build()));
	}
	
	@GetMapping("/export")
	public ResponseEntity<Resource> getEventExport(HttpServletRequest request) throws ServletRequestBindingException, IOException {
        List<Map<String,Object>> record = appreciationService.listReport(CriteriaArgsBuilder.withRequest(request)
				.addInteger("id")
				.addString("sbuIds")
				.addIntegerList("categoryIds")
				.addStringLike("clientDepOrOrg")
				.addStringLike("clientName")
				.addDate("receiptDateFrom")
				.addDateTo("receiptDateTo")
				.addDate("lnReceiptDateFrom")
				.addDateTo("lnReceiptDateTo")
				.addDate("clientReplyDateFrom")
				.addDateTo("clientReplyDateTo")
				.addDate("staffReplyDateFrom")
				.addDateTo("staffReplyDateTo")
				.build());
		
		for (Map<String, Object> appreciation : record) {
			String sbuIds = (String) appreciation.get("sbuIds");
			ObjectMapper objectMapper = new ObjectMapper();
			List<Map<String,Object>> ids = objectMapper.readValue(sbuIds, List.class);
			String divisionString = "";
			int count = 0;
			for (Map<String,Object> map : ids) {
				if(count != 0){
					divisionString += ", ";
				}
				divisionString += sbuDivisionService.getDivisionNameById(map);
				count++;
			}
			appreciation.put("divisionString", divisionString);
		}
		
		byte[] reportResult = excelReportService.generateAppreciationExcelReport(record);
		final DateTimeFormatter fileDateFormat = DateTimeFormatter.ofPattern("YYYYMMdd");

		return ResponseEntity.ok()
				.header("filename", "appreciation_export_" + LocalDate.now().format(fileDateFormat) + ".xlsx")
				.body(new ByteArrayResource(reportResult));
    }

	@GetMapping("/fileRef/{id}")
	public RecordsRes<Map<String, Object>> getFileRefList(@PathVariable Long id) throws ServletRequestBindingException {
		return new RecordsRes<>(fileService.listFile(
				Map.of(
                    "refId",id,
                    "refType", "appreciation"
                )
        ));
	}

    @GetMapping("/storedSize/{id}")
	public Map<String, Object> getFileStoredSize(@PathVariable Long id) throws ServletRequestBindingException {
		BigDecimal size = fileRefService.getFileStoredSize(
            Map.of(
                "refId",id,
                "refType", "appreciation"
            ));
        
        return Map.of("size", size);
	}

	@GetMapping("/downloadTemplate")
	public ResponseEntity<Resource> getImportTemplate() throws IOException {
		byte[] reportResult = excelReportService.exportAppreciationTemplate();
		return ResponseEntity.ok()
		.header("filename", "Appreciation_Records_Import_Template_v1.0.xlsx")
		.body(new ByteArrayResource(reportResult));
    }

    @RequestMapping(value = "/caseReport", method = RequestMethod.GET)
	public ResponseEntity<Resource> downloadAppreciationsCaseReport(HttpServletRequest request) throws Exception {
		String lnReceiptDateFrom = request.getParameter("dateFrom");
    	String lnReceiptDateTo = request.getParameter("dateTo");

		LocalDate dateFrom = LocalDate.parse(lnReceiptDateFrom);
		LocalDate dateTo = LocalDate.parse(lnReceiptDateTo).plusDays(1);

		byte[] reportResult = appreciationService.generateCaseReport(dateFrom,dateTo);
		final DateTimeFormatter fileDateFormat = DateTimeFormatter.ofPattern("YYYYMMdd");
		
        return ResponseEntity.ok()
                    .header("filename", "Appreciation_Cases_Report_" + LocalDate.now().format(fileDateFormat) + ".docx")
                    .body(new ByteArrayResource(reportResult));
	}

	@RequestMapping(value = "/summaryReport", method = RequestMethod.GET)
	public ResponseEntity<Resource> downloadAppreciationsSummaryReport(HttpServletRequest request) throws Exception {
		Integer year = Integer.parseInt(request.getParameter("year"));
    	Integer month = Integer.parseInt(request.getParameter("month"));

		// final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("YYYYMMM");
		// String reportPeriod = LocalDate.of(year,month,1).format(dateFormat);

		final DateTimeFormatter fileDateFormat = DateTimeFormatter.ofPattern("YYYYMMdd");

		byte[] reportResult = appreciationService.generateSummaryReport(year,month);
		
        return ResponseEntity.ok()
                    .header("filename", "Appreciation_Summary_Report_" + LocalDate.now().format(fileDateFormat) + ".docx")
                    .body(new ByteArrayResource(reportResult));
	}

	@PostMapping("/errorExport")
	public ResponseEntity<Resource> downloadAppreciationsImportErrorReport(@RequestBody @Valid CreateImportErrorReportReq req) throws Exception {

		byte[] reportResult = appreciationService.generateImportErrorReport(req.getErrorRecord());
		
		final DateTimeFormatter fileDateFormat = DateTimeFormatter.ofPattern("YYYYMMdd");

        return ResponseEntity.ok()
                    .header("filename", "Appreciation_Import_Error_Report_" + LocalDate.now().format(fileDateFormat) + ".xlsx")
                    .body(new ByteArrayResource(reportResult));
	}
}



