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

import java.io.IOException;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

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.CacheControl;
import org.springframework.http.HttpStatus;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.ffii.lioner.modules.lioner.req.UpdateEventReq;
import com.ffii.lioner.modules.lioner.service.EventService;
import com.ffii.lioner.modules.common.service.ExcelReportService;
import com.ffii.core.exception.NotFoundException;
import com.ffii.core.response.DataRes;
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("/event")
public class EventController{

    private final Log logger = LogFactory.getLog(getClass());
	private EventService eventService;
	private ExcelReportService excelReportService;

    public EventController(EventService eventService, ExcelReportService excelReportService) {
        this.eventService = eventService;
		this.excelReportService = excelReportService;
	}

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

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
	@PostMapping("/save")
	public Map<String, Object> saveOrUpdate(@RequestBody @Valid UpdateEventReq req) {
		return Map.of(
				Params.DATA,eventService.saveOrUpdate(req)
			);
	}

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

    @GetMapping
	public RecordsRes<Map<String, Object>> list(HttpServletRequest request) throws ServletRequestBindingException {
		return new RecordsRes<>(eventService.list(
				CriteriaArgsBuilder.withRequest(request)
						.addStringLike("eventName")
                        .addStringLike("description")
                        .addStringLike("organization")
                        .addDate("fromDate")
                        .addDateTo("toDate")
                        .addStringLike("region")
                        .addStringLike("type")
                        .addIntegerList("divisionIdList")
                        .addIntegerList("subDivisionIdList")
                        .addStringLike("keyword")
						.build()));
	}
	
	@GetMapping("/export")
	public ResponseEntity<Resource> getEventExport(HttpServletRequest request) throws ServletRequestBindingException, IOException {
        List<Map<String,Object>> record = eventService.listReport(CriteriaArgsBuilder.withRequest(request)
					.addStringLike("eventName")
					.addStringLike("description")
					.addStringLike("organization")
					.addDate("fromDate")
					.addDateTo("toDate")
					.addStringLike("region")
					.addStringLike("type")
					.addIntegerList("divisionIdList")
					.addIntegerList("subDivisionIdList")
					.addStringLike("keyword")
					.build());
		
		byte[] reportResult = excelReportService.generateEventExcelReport(record);
		return ResponseEntity.ok()
				.header("filename", "event_export_" + LocalDate.now())
				.body(new ByteArrayResource(reportResult));
    }

	@GetMapping("/application")
	public RecordsRes<Map<String, Object>> listByEvent(HttpServletRequest request) 
	throws ServletRequestBindingException {
		return new RecordsRes<>(eventService.listByEvent(
				CriteriaArgsBuilder.withRequest(request)
			.addInteger("eventId")
			.addInteger("userSubDivisionId")
			.build()
		));
	}

    @GetMapping("/combo")
	public RecordsRes<Map<String, Object>> getEventCombo(HttpServletRequest request) throws ServletRequestBindingException {
		System.out.println(request);
		return new RecordsRes<>(eventService.listCombo(
				CriteriaArgsBuilder.withRequest(request)
						.addInteger("userSubDivisionId")
						.build()));
	}

	@GetMapping("/checkDuplicate")
    public Map<String, Boolean> checkDuplicate(@RequestParam String name, @RequestParam Long id) {
        boolean isNameTaken = eventService.isNameTaken(name,id);
        return Map.of(
            "isTaken", isNameTaken

        );
    }

	@GetMapping("/checkOvertime/{id}")
    public Map<String, Object> checkOvertime(@PathVariable Long id) {
        return eventService.isReminderOvertime(id);
    }
	
	@GetMapping("/dashboard/combo")
    public RecordsRes<Map<String, Object>> getDashboardCombo() {
        return new RecordsRes<>(eventService.getDashboardCombo());
    }

	@GetMapping("/dashboard/topRecord")
    public RecordsRes<Map<String, Object>> getTop6(HttpServletRequest request) throws ServletRequestBindingException {
        return new RecordsRes<>(eventService.getTop6(
			CriteriaArgsBuilder.withRequest(request)
						.addInteger("year")
						.addInteger("userSubDivisionId")
						.build()
		));
    }
	
	@GetMapping("/dashboard/yearAward")
    public DataRes<Map<String, Object>> getYearAwardCount(HttpServletRequest request) throws ServletRequestBindingException {
        return new DataRes<>(eventService.getYearAwardCount(
			CriteriaArgsBuilder.withRequest(request)
						.addInteger("year")
						.addInteger("userSubDivisionId")
						.build()
		));
    }

	@GetMapping("/dashboard/yearEvent")
	public DataRes<Map<String, Object>> getYearEventCount(HttpServletRequest request) throws ServletRequestBindingException {
        return new DataRes<>(eventService.getYearEventCount(
			CriteriaArgsBuilder.withRequest(request)
						.addInteger("year")
						.addInteger("userSubDivisionId")
						.build()
		));
    }

	@GetMapping("/dashboard/yearDivisionSummary")
	public RecordsRes<Map<String, Object>> getDivisionAwardSummary(@RequestParam Integer year, @RequestParam String branch,  @RequestParam Boolean viewDivisionOnly, @RequestParam Integer userSubDivisionId) {
		if(!viewDivisionOnly){
			List<Map<String,Object>> tempRecords = eventService.getDivisionAwardSummary(Map.of("year",year, "branch", branch));
		
			if(tempRecords.size() == 0){
				tempRecords = eventService.getDummyDivisionAwardSummary(Map.of("year",year,"branch", branch));
			}
			return new RecordsRes<>(tempRecords);

		}
		else{
			List<Map<String,Object>> tempRecords = eventService.getDummyDivisionAwardSummary(Map.of("year",year,"userSubDivisionId",userSubDivisionId));
			return new RecordsRes<>(tempRecords);

		}

    }

	@GetMapping("/dashboard/yearTagSummary")
	public RecordsRes<Map<String, Object>> getTagAwardSummary(HttpServletRequest request) throws ServletRequestBindingException {
        return new RecordsRes<>(eventService.getTagAwardSummary(
			CriteriaArgsBuilder.withRequest(request)
						.addInteger("year")
						.addInteger("userSubDivisionId")
						.build()
		));
    }
	
	@GetMapping("/dashboard/yearCategorySummary")
	public RecordsRes<Map<String, Object>> getCategoryAwardSummary(HttpServletRequest request) throws ServletRequestBindingException {
        return new RecordsRes<>(eventService.getCategoryAwardSummary(
			CriteriaArgsBuilder.withRequest(request)
						.addInteger("year")
						.addInteger("userSubDivisionId")
						.build()
		));
    }

	@GetMapping("/dashboard/awardSummaryReport")
	public ResponseEntity<Resource> getAwardSummaryReport(@RequestParam Integer year, 
	@RequestParam Integer userSubDivisionId,
	@RequestParam String branch,
	@RequestParam Boolean viewDivisionOnly
	) throws IOException {
		if(!viewDivisionOnly){
			List<Map<String,Object>> result = eventService.getAwardSummaryReportPage1(Map.of("year",year, "branch", branch));
			List<Map<String,Object>> detailResult = eventService.getAwardSummaryReportPage2(Map.of("year",year, "branch", branch));
			byte[] reportResult = excelReportService.generateDashboardExcelReport(result, detailResult, year);
			return ResponseEntity.ok()
			.header("filename", "award_summary_report_" + LocalDate.now())
			.body(new ByteArrayResource(reportResult));
		}
		else{
			List<Map<String,Object>> result = eventService.getAwardSummaryReportPage1(Map.of("year",year, "userSubDivisionId", userSubDivisionId));
			List<Map<String,Object>> detailResult = eventService.getAwardSummaryReportPage2(Map.of("year",year, "userSubDivisionId", userSubDivisionId));
			byte[] reportResult = excelReportService.generateDashboardExcelReport(result, detailResult, year);
			return ResponseEntity.ok()
			.header("filename", "award_summary_report_" + LocalDate.now())
			.body(new ByteArrayResource(reportResult));
		}

    }

}
