package com.madeu.config;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Value("${file.upload-path}")
    private String uploadPath;
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/cdn/**")
                .addResourceLocations("file:" + uploadPath + "/")
                .setCachePeriod(3600)
                .resourceChain(true)
                .addResolver(new PathResourceResolver() {
                    @Override
                    protected Resource getResource(String resourcePath, Resource location) throws IOException {
                        // 1. URL 디코딩
                        String decodedPath = decodeResourcePath(resourcePath);
                        
                        // 2. 경로 정규화 (보안 검증)
                        if (!isValidPath(decodedPath)) {
                            return null;
                        }
                        
                        // 3. 리소스 찾기
                        Resource requestedResource = location.createRelative(decodedPath);
                        
                        // 4. 존재 여부 및 허용된 파일 타입 검증
                        if (requestedResource.exists() && 
                            requestedResource.isReadable() && 
                            isAllowedResource(requestedResource)) {
                            return requestedResource;
                        }
                        
                        return null;
                    }
                    
                    private String decodeResourcePath(String path) {
                        try {
                            // UTF-8로 URL 디코딩
                            return URLDecoder.decode(path, StandardCharsets.UTF_8.name());
                        } catch (Exception e) {
                            // 디코딩 실패 시 원본 반환
                            return path;
                        }
                    }
                    
                    private boolean isValidPath(String path) {
                        // 경로 탐색 공격 방지 (../ 등)
                        if (path.contains("..") || path.contains("./")) {
                            return false;
                        }
                        
                        // 절대 경로 방지
                        if (path.startsWith("/") || path.contains(":")) {
                            return false;
                        }
                        
                        return true;
                    }
                    
                    private boolean isAllowedResource(Resource resource) {
                        try {
                            String filename = resource.getFilename();
                            if (!StringUtils.hasText(filename)) {
                                return false;
                            }
                            
                            // 허용된 확장자 체크
                            String lowerFilename = filename.toLowerCase();
                            return lowerFilename.endsWith(".jpg") || 
                                   lowerFilename.endsWith(".jpeg") || 
                                   lowerFilename.endsWith(".png") || 
                                   lowerFilename.endsWith(".gif") || 
                                   lowerFilename.endsWith(".webp") ||
                                   lowerFilename.endsWith(".bmp") ||
                                   lowerFilename.endsWith(".svg");
                        } catch (Exception e) {
                            return false;
                        }
                    }
                });
    }
}