package com.owrawww.controller;

import com.owrawww.domain.Careers;
import com.owrawww.service.CareersService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Controller
@RequestMapping("/careers/recruitment")
@RequiredArgsConstructor
public class CareersController {
//테스트123
    private static final long        MAX_FILE_SIZE = 10 * 1024 * 1024L;
    private static final Set<String> ALLOWED_EXT   = Set.of(
            "pdf", "doc", "docx", "hwp", "hwpx", "ppt", "pptx", "txt", "zip"
    );

    // 파일 매직 바이트 시그니처
    private static final byte[] MAGIC_PDF  = {0x25, 0x50, 0x44, 0x46};                                             // %PDF
    private static final byte[] MAGIC_OLE2 = {(byte)0xD0, (byte)0xCF, 0x11, (byte)0xE0, (byte)0xA1, (byte)0xB1, 0x1A, (byte)0xE1}; // DOC/XLS/PPT/HWP(5)
    private static final byte[] MAGIC_ZIP  = {0x50, 0x4B, 0x03, 0x04};                                             // DOCX/XLSX/PPTX/HWPX (ZIP 기반)
    private static final byte[] MAGIC_HWP5 = {0x48, 0x57, 0x50, 0x20, 0x44, 0x6F, 0x63, 0x75};                   // "HWP Docu" (HWP 5.x)

    private final CareersService careersService;

    @GetMapping
    public String careersForm(@ModelAttribute Careers careers) {
        return "sub03_04";
    }

    @PostMapping
    @ResponseBody
    public ResponseEntity<Map<String, Object>> careersSubmit(
            @Valid @ModelAttribute Careers careers,
            BindingResult bindingResult,
            @RequestParam(value = "file", required = false) MultipartFile file) {

        Map<String, Object> result = new HashMap<>();

        if (bindingResult.hasErrors()) {
            result.put("success", false);
            result.put("message", "입력값을 확인해주세요.");
            return ResponseEntity.badRequest().body(result);
        }

        if (file != null && !file.isEmpty()) {
            // 용량 검증
            if (file.getSize() > MAX_FILE_SIZE) {
                result.put("success", false);
                result.put("message", "파일 용량은 10MB 이하만 가능합니다.");
                return ResponseEntity.badRequest().body(result);
            }

            // 확장자 검증
            String originalName = file.getOriginalFilename() != null ? file.getOriginalFilename() : "";
            String ext = originalName.contains(".")
                    ? originalName.substring(originalName.lastIndexOf('.') + 1).toLowerCase()
                    : "";
            if (!ALLOWED_EXT.contains(ext)) {
                result.put("success", false);
                result.put("message", "허용된 파일 형식이 아닙니다. (PDF, Word, 한글, PPT, 텍스트)");
                return ResponseEntity.badRequest().body(result);
            }

            // 파일 내용(매직 바이트) 검증
            try {
                String contentError = validateFileContent(file, ext);
                if (contentError != null) {
                    result.put("success", false);
                    result.put("message", contentError);
                    return ResponseEntity.badRequest().body(result);
                }
            } catch (IOException e) {
                result.put("success", false);
                result.put("message", "파일을 읽는 중 오류가 발생했습니다.");
                return ResponseEntity.badRequest().body(result);
            }
        }

        try {
            boolean success = careersService.submit(careers, file);
            result.put("success", success);
            if (!success) {
                result.put("message", "처리 중 오류가 발생했습니다. 다시 시도해주세요.");
            }
        } catch (IOException e) {
            result.put("success", false);
            result.put("message", "파일 저장 중 오류가 발생했습니다.");
            return ResponseEntity.internalServerError().body(result);
        }
        return ResponseEntity.ok(result);
    }

    /**
     * 파일 매직 바이트로 실제 형식 검증
     * - PDF  : %PDF 시그니처
     * - DOC/XLS/PPT/HWP(5) : OLE2 복합 문서 시그니처
     * - DOCX/XLSX/PPTX/HWPX : ZIP(PK) 시그니처
     * - TXT  : 바이너리 제어문자 미포함 여부
     */
    private String validateFileContent(MultipartFile file, String ext) throws IOException {
        byte[] header = new byte[8];
        try (InputStream is = file.getInputStream()) {
            int read = is.read(header);
            if (read < 4) {
                return "파일이 손상되었거나 내용이 없습니다.";
            }
        }
 
        return switch (ext) {
            case "pdf" -> startsWith(header, MAGIC_PDF)
                    ? null : "PDF 파일 형식이 올바르지 않습니다.";

            case "doc", "xls", "ppt" -> startsWith(header, MAGIC_OLE2) || startsWith(header, MAGIC_HWP5)
                    ? null : "파일 내용이 선택한 형식(" + ext.toUpperCase() + ")과 일치하지 않습니다.";

            case "hwp" -> startsWith(header, MAGIC_OLE2) || startsWith(header, MAGIC_HWP5) || startsWith(header, MAGIC_ZIP)
                    ? null : "HWP 파일 형식이 올바르지 않습니다.";

            case "docx", "xlsx", "pptx", "hwpx" -> startsWith(header, MAGIC_ZIP)
                    ? null : "파일 내용이 선택한 형식(" + ext.toUpperCase() + ")과 일치하지 않습니다.";

            case "zip" -> startsWith(header, MAGIC_ZIP)
                    ? null : "ZIP 파일 형식이 올바르지 않습니다.";

            case "txt" -> isPlainText(header)
                    ? null : "TXT 파일에 허용되지 않는 바이너리 내용이 포함되어 있습니다.";

            default -> "허용된 파일 형식이 아닙니다.";
        };
    }

    private boolean startsWith(byte[] data, byte[] magic) {
        if (data.length < magic.length) return false;
        for (int i = 0; i < magic.length; i++) {
            if (data[i] != magic[i]) return false;
        }
        return true;
    }

    /** TXT: 제어문자(탭·개행 제외)가 없으면 텍스트로 판단 */
    private boolean isPlainText(byte[] header) {
        for (byte b : header) {
            int c = b & 0xFF;
            if (c < 0x09) return false;                   // 0x00~0x08 제어문자
            if (c == 0x0B || c == 0x0C) return false;     // VT, FF
            if (c >= 0x0E && c <= 0x1F) return false;     // 기타 제어문자
        }
        return true;
    }
}
