package incheon.uis.ums.util;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import lombok.RequiredArgsConstructor;
import org.egovframe.rte.fdl.property.EgovPropertyService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import incheon.com.cmm.context.RequestContext;
import incheon.com.utl.fcc.service.EgovStringUtil;
import incheon.uis.ucf.model.UisDefaultModel;
import incheon.uis.ums.file.vo.CmtFileVO;
import incheon.uis.ums.service.DynamicModelService;
import incheon.uis.ums.service.impl.UisFacilityServiceImpl;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@RequiredArgsConstructor
public class UisFileUtils {

    @Resource(name = "propertiesService")
    protected EgovPropertyService propertyService;

    @Resource(name = "dynamicModelService")
    protected DynamicModelService dynamicModelService;

    @Value("${uis.fileStorePath}")
    private String uisFileStorePath;  // 예) /home/incheon/env/apps/resources/uis/ums/shp/

    /**
     * 업로드된 파일 저장
     * @param file 업로드할 파일
     * @param gubun 시설구분
     * @param entity 테이블
     * @param request HttpServletRequest
     * @return CmtFileVO
     * @throws IOException
     */
    public CmtFileVO saveUploadedFile(MultipartFile file, String entity, HttpServletRequest request) throws IOException {
        // 1. 원본 파일명
        String originalFilename = file.getOriginalFilename();

        // 2. 파일 확장자
        String extension = getFileExtension(originalFilename);


        //3. 2025-11-11 seyoung : 기존 루트 분류체계에 맞게 수정
        String[] entityParts = entity.split("_");
        entity = entityParts[1].toUpperCase(Locale.ROOT);
        String gubun = entityParts[0].toUpperCase(Locale.ROOT);

        //4. 서버 저장 파일명 생성 (구분 + 타임스탬프) ex. rdl_20251111090009
        String serverFilename = generateServerFilename(extension, gubun);

        // 5. 저장 경로 생성 (년/월 기준)
        // 현재 날짜 가져오기
        LocalDate now = LocalDate.now();
        String folderPath = String.format("/%s/%s/%04d/%02d",
                gubun.toUpperCase(Locale.ROOT),
                entity,
                now.getYear(),
                now.getMonthValue()
        );
        String path = normalizeToRelativePath(folderPath);

        // 6. 전체 경로 생성
        String basePath= uisFileStorePath;

        Path fullFolderPath = Paths.get(basePath).resolve(path).normalize();

        // 7. 폴더 생성 (없으면)
        if (!Files.exists(fullFolderPath)) {
            Files.createDirectories(fullFolderPath);
        }

        // 8. 파일 저장
        Path filePath = fullFolderPath.resolve(serverFilename).normalize();
        file.transferTo(filePath.toFile());

        // 9. VO 생성
        CmtFileVO fileVO = new CmtFileVO();
        fileVO.setDwnldFileNm(originalFilename);
        fileVO.setSrvrStrgFileNm(serverFilename);
        fileVO.setAtchFileExtnNm(extension);
        fileVO.setFldrPathNm(folderPath.toString());
        fileVO.setOrgnlFileSz(BigDecimal.valueOf(file.getSize()));
        //fileVO.setRmrkCn(rmrkCn);
        fileVO.setUseYn("Y");

        // 10. 사용자 정보 설정 (세션에서 가져오기)
        String userId = RequestContext.getCurrentUserId();
        if(userId != null) {
          fileVO.setFrstRegId(userId);
          fileVO.setLastMdfcnId(userId);
        }

        return fileVO;
    }

    /**
     * 파일 경로 추출
     * @param path 파일 경로, fileName
     * @return Path path
     */
    public Path getFullPath(String path, String fileName) throws FileNotFoundException {
        String fileStorePath = uisFileStorePath;

        if (fileStorePath == null || fileStorePath.trim().isEmpty()) {
            throw new IllegalStateException("uis.fileStorePath is not configured");
        }

        Path basePath = Paths.get(fileStorePath);

        // path를 상대 경로로 변환
        String cleanPath = normalizeToRelativePath(path);

        // OS에 맞게 경로 조합
        Path fullPath = basePath.resolve(cleanPath).resolve(fileName).normalize();

        if (!Files.exists(fullPath)) {
            throw new FileNotFoundException("Image file not found: " + fullPath);
        }

        return fullPath;
    }

    /**
     * 파일 경로
     * @param path 파일 경로
     * @return String Path
     */
    public static String normalizeToRelativePath(String path) {
        if (path == null || path.isEmpty()) {
            return "";
        }

        String cleaned = path;

        // Windows 드라이브 문자 제거 (C:\, D:\, etc.)
        cleaned = cleaned.replaceFirst("^[A-Za-z]:[/\\\\]*", "");

        // 절대 경로 표시 제거 (/, \, //, \\, etc.)
        cleaned = cleaned.replaceFirst("^[/\\\\]+", "");

        // 백슬래시를 슬래시로 통일 (Path API가 OS에 맞게 변환)
        cleaned = cleaned.replace("\\", "/");

        return cleaned;
    }


    /**
     * 파일명 인코딩 (한글 파일명 처리)
     * @param filename 원본 파일명
     * @return 인코딩된 파일명
     */
    public String encodeFilename(String filename) {
        try {
            return URLEncoder.encode(filename, StandardCharsets.UTF_8.toString())
                    .replaceAll("\\+", "%20"); // 공백 처리
        } catch (Exception e) {
            return filename;
        }
    }

    /**
     * 이미지 파일 확장자에 따른 Content-Type 반환
     * @param filename 파일명
     * @return Content-Type (이미지가 아닐 경우 null)
     */
    public String getImageContentType(String filename) {
        String extension = "";
        int lastDotIndex = filename.lastIndexOf('.');
        if (lastDotIndex > 0) {
            extension = filename.substring(lastDotIndex + 1).toLowerCase();
        }

        return switch (extension) {
            case "jpg", "jpeg" -> "image/jpeg";
            case "png" -> "image/png";
            case "gif" -> "image/gif";
            case "bmp" -> "image/bmp";
            case "svg" -> "image/svg+xml";
            case "webp" -> "image/webp";
            case "ico" -> "image/x-icon";
            case "tiff", "tif" -> "image/tiff";
            default -> null; // 이미지가 아님
        };
    }

    /**
     * 파일 확장자에 따른 Content-Type 반환
     * @param filename 파일명
     * @return Content-Type
     */
    public String getContentType(String filename) {
        String extension = "";
        int lastDotIndex = filename.lastIndexOf('.');
        if (lastDotIndex > 0) {
            extension = filename.substring(lastDotIndex + 1).toLowerCase();
        }

        return switch (extension) {
            // 이미지
            case "jpg", "jpeg" -> "image/jpeg";
            case "png" -> "image/png";
            case "gif" -> "image/gif";
            case "bmp" -> "image/bmp";
            case "svg" -> "image/svg+xml";
            case "webp" -> "image/webp";

            // 문서
            case "pdf" -> "application/pdf";
            case "doc" -> "application/msword";
            case "docx" -> "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
            case "xls" -> "application/vnd.ms-excel";
            case "xlsx" -> "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            case "ppt" -> "application/vnd.ms-powerpoint";
            case "pptx" -> "application/vnd.openxmlformats-officedocument.presentationml.presentation";
            case "txt" -> "text/plain";
            case "csv" -> "text/csv";
            case "html", "htm" -> "text/html";

            // 압축
            case "zip" -> "application/zip";
            case "rar" -> "application/x-rar-compressed";
            case "7z" -> "application/x-7z-compressed";
            case "tar" -> "application/x-tar";
            case "gz" -> "application/gzip";

            // 비디오
            case "mp4" -> "video/mp4";
            case "avi" -> "video/x-msvideo";
            case "mov" -> "video/quicktime";
            case "wmv" -> "video/x-ms-wmv";

            // 오디오
            case "mp3" -> "audio/mpeg";
            case "wav" -> "audio/wav";
            case "ogg" -> "audio/ogg";

            // 기타
            case "json" -> "application/json";
            case "xml" -> "application/xml";
            default -> "application/octet-stream"; // 기본값 (바이너리 다운로드)
        };
    }

    /**
     * 파일 확장자 추출
     * @param filename 파일명
     * @return 확장자
     */
    public String getFileExtension(String filename) {
        if (filename == null || filename.isEmpty()) {
            return "";
        }

        int lastDotIndex = filename.lastIndexOf('.');
        if (lastDotIndex > 0 && lastDotIndex < filename.length() - 1) {
            return filename.substring(lastDotIndex + 1).toLowerCase();
        }

        return "";
    }

    /**
     * 서버 저장 파일명 생성
     * @param extension 파일 확장자
     * @return 서버 저장 파일명
     */
    private String generateServerFilename(String extension, String gubun) {
        String timestamp = EgovStringUtil.getTimeStamp();

        if (extension != null && !extension.isEmpty()) {
            return gubun + "_" + timestamp + "." + extension;
        }

        return gubun + "_" + timestamp;
    }

    /**
     * 허용된 파일 확장자 확인
     * @param extension 파일 확장자
     * @return 허용 여부
     */
    public boolean isAllowedExtension(String extension) {
        if (extension == null || extension.isEmpty()) {
            return false;
        }

        // 허용할 확장자 목록
        Set<String> allowedExtensions = new HashSet<>(Arrays.asList(
                // 이미지
                "jpg", "jpeg", "png", "gif", "bmp", "svg", "webp",
                // 문서
                "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "csv",
                // 압축
                "zip", "rar", "7z"
        ));

        return allowedExtensions.contains(extension.toLowerCase());
    }
}
