package go.kr.project.system.loginLog.controller;

import egovframework.constant.MessageConstants;
import egovframework.constant.TilesConstants;
import egovframework.util.ApiResponseUtil;
import egovframework.util.excel.ExcelSheetData;
import egovframework.util.excel.SxssfExcelFile;
import go.kr.project.system.loginLog.model.LoginLogSearchVO;
import go.kr.project.system.loginLog.model.LoginLogStatsVO;
import go.kr.project.system.loginLog.model.LoginLogVO;
import go.kr.project.system.loginLog.service.LoginLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * packageName    : go.kr.project.login.controller
 * fileName       : LoginLogController
 * author         : 시스템 관리자
 * date           : 2025-05-13
 * description    : 로그인 로그 관련 컨트롤러
 * ===========================================================
 * DATE              AUTHOR             NOTE
 * -----------------------------------------------------------
 * 2025-05-13        시스템 관리자       최초 생성
 */
@RequestMapping("/system/loginLog")
@Controller
@RequiredArgsConstructor
@Slf4j
@Tag(name = "시스템: 로그인 로그", description = "로그인 로그 관련 API")
public class LoginLogController {

    private final LoginLogService loginLogService;

    /**
     * 로그인 로그 목록 페이지를 표시합니다.
     * 
     * @param model 모델 객체
     * @return 로그인 로그 목록 페이지 뷰
     */
    @Operation(summary = "로그인 로그 목록 페이지", description = "로그인 로그 목록 페이지를 표시합니다.")
    @GetMapping("/list.do")
    public String listPage(Model model) {
        return "system/loginLog/list"+ TilesConstants.BASE;
    }

    /**
     * 로그인 로그 목록을 조회합니다. (AJAX)
     * 
     * @param paramVO 조회 조건
     * @return 로그인 로그 목록과 성공 상태를 담은 ResponseEntity 객체
     */
    @Operation(summary = "로그인 로그 목록 조회", description = "조건에 맞는 로그인 로그 목록을 조회합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "조회 성공"),
        @ApiResponse(responseCode = "400", description = "조회 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/list.ajax")
    public ResponseEntity<?> listAjax(@ModelAttribute LoginLogSearchVO paramVO) {
        // 로그인 로그 목록 조회
        int totalCount = loginLogService.getLoginLogCount(paramVO);
        paramVO.setTotalCount(totalCount);

        // 페이징 처리를 위한 설정
        paramVO.setPagingYn("Y");
        List<LoginLogVO> list = loginLogService.getLoginLogList(paramVO);

        return ApiResponseUtil.successWithGrid(list, paramVO);
    }


    /**
     * 로그인 로그 상세 정보를 조회합니다. (AJAX)
     * 
     * @param logId 로그 ID
     * @return 로그인 로그 상세 정보와 성공 상태를 담은 ResponseEntity 객체
     */
    @Operation(summary = "로그인 로그 상세 조회", description = "로그인 로그 상세 정보를 조회합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "조회 성공"),
        @ApiResponse(responseCode = "400", description = "조회 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @GetMapping("/{logId}/detail.ajax")
    public ResponseEntity<?> detailAjax(@PathVariable("logId") String logId) {
        LoginLogVO loginLog = loginLogService.getLoginLog(logId);

        if (loginLog == null) {
            return ApiResponseUtil.error(MessageConstants.LoginLog.NOT_EXIST);
        }

        return ApiResponseUtil.success(loginLog, MessageConstants.LoginLog.DETAIL_SUCCESS);
    }

    /**
     * 통계 페이지를 표시합니다.
     * 
     * @param model 모델 객체
     * @return 통계 페이지 뷰
     */
    @Operation(summary = "로그인 로그 통계 페이지", description = "로그인 로그 통계 페이지를 표시합니다.")
    @GetMapping("/stats.do")
    public String statsPage(Model model) {
        return "system/loginLog/stats"+ TilesConstants.BASE;
    }

    /**
     * 디바이스 유형별 로그인 통계를 조회합니다. (AJAX)
     * 
     * @param params 조회 조건
     * @return 디바이스 유형별 로그인 통계와 성공 상태를 담은 ResponseEntity 객체
     */
    @Operation(summary = "디바이스 유형별 로그인 통계 조회", description = "디바이스 유형별 로그인 통계를 조회합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "조회 성공"),
        @ApiResponse(responseCode = "400", description = "조회 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/stats/device.ajax")
    public ResponseEntity<?> deviceStatsAjax(@RequestParam Map<String, Object> params) {
        List<Map<String, Object>> stats = loginLogService.getDeviceTypeStats(params);

        Map<String, Object> data = new HashMap<>();
        data.put("stats", stats);

        return ApiResponseUtil.success(data, MessageConstants.Stats.DEVICE_SUCCESS);
    }

    /**
     * 로그인 성공/실패 비율 통계를 조회합니다. (AJAX)
     * 
     * @param params 조회 조건
     * @return 로그인 성공/실패 비율 통계와 성공 상태를 담은 ResponseEntity 객체
     */
    @Operation(summary = "로그인 성공/실패 비율 통계 조회", description = "로그인 성공/실패 비율 통계를 조회합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "조회 성공"),
        @ApiResponse(responseCode = "400", description = "조회 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/stats/success-fail.ajax")
    public ResponseEntity<?> successFailStatsAjax(@RequestParam Map<String, Object> params) {
        List<Map<String, Object>> stats = loginLogService.getSuccessFailStats(params);

        Map<String, Object> data = new HashMap<>();
        data.put("stats", stats);

        return ApiResponseUtil.success(data, MessageConstants.Stats.SUCCESS_FAIL_SUCCESS);
    }

    /**
     * 시간대별 로그인 시도 통계를 조회합니다. (AJAX)
     * 
     * @param params 조회 조건
     * @return 시간대별 로그인 시도 통계와 성공 상태를 담은 ResponseEntity 객체
     */
    @Operation(summary = "시간대별 로그인 시도 통계 조회", description = "시간대별 로그인 시도 통계를 조회합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "조회 성공"),
        @ApiResponse(responseCode = "400", description = "조회 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/stats/hourly.ajax")
    public ResponseEntity<?> hourlyStatsAjax(@RequestParam Map<String, Object> params) {
        List<Map<String, Object>> stats = loginLogService.getHourlyLoginStats(params);

        Map<String, Object> data = new HashMap<>();
        data.put("stats", stats);

        return ApiResponseUtil.success(data, MessageConstants.Stats.HOURLY_SUCCESS);
    }

    /**
     * 통계 데이터를 엑셀 파일로 다운로드합니다.
     * 
     * @param params 조회 조건
     * @param request HTTP 요청 객체
     * @param response HTTP 응답 객체
     */
    @Operation(summary = "통계 데이터 엑셀 다운로드", description = "통계 데이터를 엑셀 파일로 다운로드합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "다운로드 성공"),
        @ApiResponse(responseCode = "400", description = "다운로드 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @GetMapping("/stats/excel.do")
    public void statsExcelDownload(
            @RequestParam Map<String, Object> params,
            HttpServletRequest request,
            HttpServletResponse response) {
        try {
            // 디바이스 유형별 통계 조회
            List<Map<String, Object>> deviceStats = loginLogService.getDeviceTypeStats(params);

            // 성공/실패 비율 통계 조회
            List<Map<String, Object>> successFailStats = loginLogService.getSuccessFailStats(params);

            // 시간대별 통계 조회
            List<Map<String, Object>> hourlyStats = loginLogService.getHourlyLoginStats(params);

            // 통계 데이터를 LoginLogStatsVO 리스트로 변환
            List<LoginLogStatsVO> statsList = new ArrayList<>();

            // 현재 시간을 문자열로 변환 (엑셀 파일에 생성 시간 표시용)
            String createDate = java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

            // 조회 기간 정보
            String startDate = (String) params.getOrDefault("searchStartDt", "");
            String endDate = (String) params.getOrDefault("searchEndDt", "");

            // 디바이스 유형별 통계 변환
            for (Map<String, Object> stat : deviceStats) {
                LoginLogStatsVO vo = new LoginLogStatsVO();
                vo.setStatsType("디바이스 유형별");
                vo.setItemName((String) stat.getOrDefault("deviceInfo", "알 수 없음"));
                vo.setCount(Integer.parseInt(stat.getOrDefault("count", "0").toString()));
                vo.setStartDate(startDate);
                vo.setEndDate(endDate);
                vo.setCreateDate(createDate);
                statsList.add(vo);
            }

            // 성공/실패 비율 통계 변환
            for (Map<String, Object> stat : successFailStats) {
                LoginLogStatsVO vo = new LoginLogStatsVO();
                vo.setStatsType("성공/실패 비율");
                String successYn = (String) stat.getOrDefault("successYn", "");
                vo.setItemName("Y".equals(successYn) ? "성공" : "N".equals(successYn) ? "실패" : "알 수 없음");
                vo.setCount(Integer.parseInt(stat.getOrDefault("count", "0").toString()));
                vo.setStartDate(startDate);
                vo.setEndDate(endDate);
                vo.setCreateDate(createDate);
                statsList.add(vo);
            }

            // 시간대별 통계 변환
            for (Map<String, Object> stat : hourlyStats) {
                LoginLogStatsVO vo = new LoginLogStatsVO();
                vo.setStatsType("시간대별");
                vo.setItemName(stat.getOrDefault("hour", "0") + "시");
                vo.setCount(Integer.parseInt(stat.getOrDefault("count", "0").toString()));
                vo.setSuccessCount(Integer.parseInt(stat.getOrDefault("successCount", "0").toString()));
                vo.setFailCount(Integer.parseInt(stat.getOrDefault("failCount", "0").toString()));
                vo.setStartDate(startDate);
                vo.setEndDate(endDate);
                vo.setCreateDate(createDate);
                statsList.add(vo);
            }

            // 엑셀 파일 생성 및 다운로드
            String filename = "로그인_통계_" + createDate.replaceAll("[^0-9]", "") + ".xlsx";
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

            // 엑셀 파일 생성
            new SxssfExcelFile(ExcelSheetData.of(statsList, LoginLogStatsVO.class), request, response, filename);

        } catch (Exception e) {
            log.error("통계 데이터 엑셀 다운로드 중 오류 발생", e);
        }
    }
}
