package com.eactive.eai.rms.onl.apim.portalterms;

import com.eactive.apim.portal.file.entity.FileDetail;
import com.eactive.apim.portal.file.entity.FileInfo;
import com.eactive.apim.portal.file.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 에디터 이미지 서비스
 * - summernote 에디터에서 사용하는 이미지 업로드/조회/삭제 서비스
 * - FileService를 래핑하여 이미지 전용 기능 제공
 */
@Service
@Transactional(transactionManager = "transactionManagerForEMS")
@Slf4j
public class EditorImageService {

    /**
     * 플레이스홀더 패턴: {{IMG:fileId:fileSn}} 또는 {{IMG:fileId:fileSn|속성}}
     * - fileId: UUID 형식 (예: 550e8400-e29b-41d4-a716-446655440000)
     * - fileSn: 정수 (예: 1)
     * - 속성: 선택적 (예: |width=300|height=200|style=max-width:100%)
     */
    private static final Pattern PLACEHOLDER_PATTERN =
            Pattern.compile("\\{\\{IMG:([a-f0-9\\-]+):(\\d+)(\\|[^}]+)?\\}\\}");

    private final FileService fileService;

    @Autowired
    public EditorImageService(FileService fileService) {
        this.fileService = fileService;
    }

    /**
     * 이미지 저장
     *
     * @param file MultipartFile 이미지 파일
     * @return EditorImageDTO (fileId, fileSn 포함)
     * @throws IOException 파일 처리 중 오류 발생 시
     */
    public EditorImageDTO saveImage(MultipartFile file) throws IOException {
        String fileName = file.getOriginalFilename();
        String contentType = file.getContentType();
        byte[] data = file.getBytes();

        // FileService를 통해 저장
        FileInfo fileInfo = fileService.createSingleFileFromBytes(fileName, contentType, data);
        FileDetail detail = fileInfo.getFileDetails().get(0);

        // DTO로 변환하여 반환
        EditorImageDTO dto = new EditorImageDTO();
        dto.setFileId(fileInfo.getFileId());
        dto.setFileSn(detail.getFileSn());
        dto.setOriginalFileName(detail.getOriginalFileName());
        dto.setFileExtension(detail.getFileExtension());
        dto.setFileSize(detail.getFileSize());

        return dto;
    }

    /**
     * 이미지 조회
     *
     * @param fileId 파일 ID
     * @param fileSn 파일 순번
     * @return EditorImageDTO (imageData 포함)
     * @throws IOException 파일 조회 중 오류 발생 시
     */
    @Transactional(readOnly = true)
    public EditorImageDTO getImage(String fileId, int fileSn) throws IOException {
        FileDetail detail = fileService.getFileDetailByIds(fileId, fileSn);
        byte[] data = fileService.retrieveFileContent(detail);

        EditorImageDTO dto = new EditorImageDTO();
        dto.setFileId(fileId);
        dto.setFileSn(fileSn);
        dto.setOriginalFileName(detail.getOriginalFileName());
        dto.setFileExtension(detail.getFileExtension());
        dto.setFileSize(detail.getFileSize());
        dto.setContentType(getContentType(detail.getFileExtension()));
        dto.setImageData(data);

        return dto;
    }

    /**
     * 본문에서 사용 중인 파일 ID 추출
     *
     * @param contents 본문 내용 (플레이스홀더 포함)
     * @return 사용 중인 파일 ID Set
     */
    public Set<String> extractFileIds(String contents) {
        Set<String> fileIds = new HashSet<>();
        if (contents == null || contents.isEmpty()) {
            return fileIds;
        }

        Matcher matcher = PLACEHOLDER_PATTERN.matcher(contents);
        while (matcher.find()) {
            fileIds.add(matcher.group(1)); // fileId
        }
        return fileIds;
    }

    /**
     * 이미지 삭제
     *
     * @param fileId 삭제할 파일 ID
     */
    public void deleteImage(String fileId) {
        try {
            fileService.deleteFile(fileId);
            log.info("Deleted image: {}", fileId);
        } catch (Exception e) {
            log.warn("Failed to delete image: {}", fileId, e);
            throw e;
        }
    }

    /**
     * 미사용 이미지 정리
     * - 원래 저장된 이미지 중 현재 본문에서 사용되지 않는 이미지 삭제
     *
     * @param usedFileIds    본문에서 사용 중인 파일 ID 목록
     * @param originalFileIds 원래 저장된 모든 파일 ID 목록
     */
    public void cleanupUnusedImages(Set<String> usedFileIds, Set<String> originalFileIds) {
        if (originalFileIds == null || originalFileIds.isEmpty()) {
            return;
        }

        for (String fileId : originalFileIds) {
            if (!usedFileIds.contains(fileId)) {
                try {
                    fileService.deleteFile(fileId);
                    log.info("Deleted unused image: {}", fileId);
                } catch (Exception e) {
                    // 삭제 실패 시 로그만 남기고 계속 진행
                    log.warn("Failed to delete unused image: {}", fileId, e);
                }
            }
        }
    }

    /**
     * 플레이스홀더를 실제 이미지 태그로 변환
     *
     * @param contents 본문 내용 (플레이스홀더 포함)
     * @param baseUrl  이미지 서빙 베이스 URL (예: /onl/apim/editor/image/view/)
     * @return 이미지 태그가 포함된 HTML
     */
    public String convertPlaceholdersToHtml(String contents, String baseUrl) {
        if (contents == null || contents.isEmpty()) {
            return contents;
        }

        StringBuffer result = new StringBuffer();
        Matcher matcher = PLACEHOLDER_PATTERN.matcher(contents);

        while (matcher.find()) {
            String fileId = matcher.group(1);
            String fileSn = matcher.group(2);
            String attrs = matcher.group(3); // |width=300|height=200 형태

            StringBuilder img = new StringBuilder();
            img.append("<img src=\"").append(baseUrl).append(fileId).append("/").append(fileSn).append("\"");

            // 속성 파싱 및 추가
            if (attrs != null && !attrs.isEmpty()) {
                String[] parts = attrs.substring(1).split("\\|"); // 앞의 | 제거 후 분리
                for (String part : parts) {
                    String[] kv = part.split("=", 2);
                    if (kv.length == 2) {
                        img.append(" ").append(kv[0]).append("=\"").append(kv[1]).append("\"");
                    }
                }
            }

            // 기본 스타일 (style 속성이 없으면 추가)
            if (attrs == null || !attrs.contains("style=")) {
                img.append(" style=\"max-width:100%;height:auto;\"");
            }

            img.append(" />");
            matcher.appendReplacement(result, Matcher.quoteReplacement(img.toString()));
        }
        matcher.appendTail(result);

        return result.toString();
    }

    /**
     * 파일 확장자를 Content-Type으로 변환
     *
     * @param extension 파일 확장자
     * @return MIME 타입
     */
    private String getContentType(String extension) {
        if (extension == null) {
            return "application/octet-stream";
        }

        switch (extension.toLowerCase()) {
            case "jpg":
            case "jpeg":
                return "image/jpeg";
            case "png":
                return "image/png";
            case "gif":
                return "image/gif";
            case "bmp":
                return "image/bmp";
            case "webp":
                return "image/webp";
            case "svg":
                return "image/svg+xml";
            default:
                return "application/octet-stream";
        }
    }
}
