package incheon.com.excel.web;

import incheon.com.excel.ExcelExportProperties;
import incheon.com.excel.ExcelExportRegistry;
import incheon.com.excel.service.CommonExcelService;
import incheon.com.excel.web.dto.CommonExcelRequestDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * 공통 엑셀 다운로드 컨트롤러
 */
@Tag(name = "공통 엑셀 다운로드 API")
@Slf4j
@RestController
@RequestMapping("/com/excel")
@RequiredArgsConstructor
public class CommonExcelController {

    private final CommonExcelService excelService;
    private final ExcelExportRegistry exportRegistry;
    private final ExcelExportProperties excelProperties;

    @Operation(summary = "엑셀 다운로드")
    @PostMapping("/download.do")
    public void downloadExcel(@RequestBody CommonExcelRequestDTO request, HttpServletResponse response) {
        String type = request.getType();
        log.info("엑셀 다운로드 요청 - type: {}", type);

        try {
            if (type == null || type.isEmpty()) {
                sendErrorResponse(response, HttpServletResponse.SC_BAD_REQUEST, "엑셀 타입이 지정되지 않았습니다.");
                return;
            }

            if (!exportRegistry.isSupported(type)) {
                sendErrorResponse(response, HttpServletResponse.SC_BAD_REQUEST, "지원하지 않는 엑셀 타입입니다");
                return;
            }

            Map<String, Object> searchParams = request.getSearchParams();
            Map<String, Object> columnMap = request.getColumnMap();

            // 페이징 여부에 따라 다른 방식으로 조회
            boolean isPaging = exportRegistry.isPaging(type);
            int pageSize = isPaging ? excelProperties.getPageSize() : Integer.MAX_VALUE;

            int totalRows = excelService.exportStream(
                    request.getFileName(),
                    columnMap,
                    response,
                    (pageNo, size) -> {
                        try {
                            // 페이징 미사용 시 첫 페이지만 조회
                            if (!isPaging && pageNo > 0) {
                                return List.of();
                            }
                            return exportRegistry.fetchDataPaged(type, searchParams, pageNo, size);
                        } catch (Exception e) {
                            log.error("조회 오류 - pageNo: {}", pageNo, e);
                            return List.of();
                        }
                    },
                    pageSize,
                    CommonExcelService.XLSX_MAX_ROWS
            );

            if (totalRows == 0) {
                sendErrorResponse(response, HttpServletResponse.SC_OK, "다운로드할 데이터가 없습니다.");
                return;
            }

            log.info("엑셀 다운로드 완료 - type: {}, rows: {}", type, totalRows);

        } catch (Exception e) {
            log.error("엑셀 다운로드 오류", e);
            sendErrorResponseSafe(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "엑셀 다운로드 중 오류가 발생했습니다.");
        }
    }

    @Operation(summary = "지원 타입 목록 조회")
    @GetMapping("/types.do")
    public ResponseEntity<Map<String, Object>> getSupportedTypes() {
        return ResponseEntity.ok(Map.of(
                "success", true,
                "types", exportRegistry.getSupportedTypes(),
                "maxRows", CommonExcelService.XLSX_MAX_ROWS
        ));
    }

    private void sendErrorResponse(HttpServletResponse response, int status, String message) throws IOException {
        response.setStatus(status);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("{\"success\":false,\"message\":\"" + message + "\"}");
    }

    private void sendErrorResponseSafe(HttpServletResponse response, int status, String message) {
        try {
            if (!response.isCommitted()) {
                sendErrorResponse(response, status, message);
            }
        } catch (IOException e) {
            log.error("에러 응답 전송 실패", e);
        }
    }
}
