package incheon.ags.dss.regen.service.impl;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import de.huxhorn.sulky.ulid.ULID;
import incheon.ags.dss.regen.mapper.UrbUserMdlDtlMapper;
import incheon.ags.dss.regen.service.UrbUserMdlDtlService;
import incheon.ags.dss.regen.vo.UrbUserMdlDtlVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service("urbUserMdlDtlService")
@RequiredArgsConstructor
@Slf4j
public class UrbUserMdlDtlServiceImpl implements UrbUserMdlDtlService {

	private final UrbUserMdlDtlMapper urbUserMdlDtlMapper;
    
    // --- 파일 업로드 표준 로직 ---
    @Value("${Globals.dss.upload.path}")
    private String uploadPath;
    
    @Value("${Globals.dss.resource.path}")
    private String resourcePath;
    
    private Path absoluteUploadPath;
    private final ULID ulid = new ULID();

    @PostConstruct
    public void init() {
        this.absoluteUploadPath = Paths.get(uploadPath).toAbsolutePath().normalize();
        log.info("사용자 모델 업로드 절대 경로: {}", this.absoluteUploadPath);
        if (!Files.exists(this.absoluteUploadPath)) {
            try {
                Files.createDirectories(this.absoluteUploadPath);
            } catch (Exception e) {
                log.error("업로드 디렉토리 생성 실패", e);
            }
        }
    }

    @Override
    public UrbUserMdlDtlVO selectUrbUserMdlDtlDetail(UrbUserMdlDtlVO vo) throws Exception {
        return urbUserMdlDtlMapper.selectUrbUserMdlDtlDetail(vo);
    }

    @Override
    public List<UrbUserMdlDtlVO> selectUrbUserMdlDtlList(UrbUserMdlDtlVO vo) throws Exception {
        return urbUserMdlDtlMapper.selectUrbUserMdlDtlList(vo);
    }

    @Override
    public int selectUrbUserMdlDtlListCnt(UrbUserMdlDtlVO vo) throws Exception {
        return urbUserMdlDtlMapper.selectUrbUserMdlDtlListCnt(vo);
    }
    
    @Override
    @Transactional
    public int saveUrbUserMdlDtl(UrbUserMdlDtlVO vo, MultipartFile file) throws Exception {
        
        // --- 1. 파일 처리 ---
        if (file != null && !file.isEmpty()) {
            log.info("새 파일 업로드 감지: {}", file.getOriginalFilename());
            
            // 1-1. (수정 시) 기존 파일 삭제 로직
            if (vo.getUserMdlNo() > 0) {
                UrbUserMdlDtlVO oldData = urbUserMdlDtlMapper.selectUrbUserMdlDtlDetail(vo);
                if (oldData != null && oldData.getFlpth() != null) {
                    try {
                        Files.deleteIfExists(Paths.get(oldData.getFlpth()));
                        log.info("기존 파일 삭제 완료: {}", oldData.getFlpth());
                    } catch (Exception e) {
                    	log.warn("기존 사용자 모델 파일 삭제 실패");
                        log.debug("Delete Failed", e);
                    }
                }
            }

            // 1-2. 새 파일 저장 (표준 로직)
            String year = String.valueOf(LocalDate.now().getYear());
            String month = String.format("%02d", LocalDate.now().getMonthValue());
            Path absoluteDirPath = absoluteUploadPath.resolve("models").resolve(year).resolve(month);
            
            if (!Files.exists(absoluteDirPath)) {
                Files.createDirectories(absoluteDirPath);
            }
            
            String orgnlFileNm = file.getOriginalFilename();
            String extension = StringUtils.getFilenameExtension(orgnlFileNm);
            String strgFileNm = ulid.nextValue().toString() + (StringUtils.hasText(extension) ? "." + extension : "");
            
            Path filePath = absoluteDirPath.resolve(strgFileNm);
            file.transferTo(filePath.toFile()); // 파일 물리적 저장
            
            // 1-3. VO에 파일 메타데이터 세팅
            String relativePath = "models/"+year + "/" + month + "/" + strgFileNm;
            String fullResourcePath = resourcePath + "/" + relativePath;
            vo.setTrgtUrl(fullResourcePath); // (예: /resources/dss/2025/11/...)
            vo.setFlpth(filePath.toString()); // (물리적 전체 경로)
            vo.setFileNm(orgnlFileNm);
            vo.setFilesiz(file.getSize());
        }
        
        // --- 2. DB 저장 ---
        if (vo.getUserMdlNo() > 0) {
            log.info("Updating UrbUserMdl (userMdlNo: {})", vo.getUserMdlNo());
            urbUserMdlDtlMapper.updateUrbUserMdlDtl(vo);
            return vo.getUserMdlNo();
        } else {
            log.info("Inserting UrbUserMdl (fileNm: {})", vo.getFileNm());
            urbUserMdlDtlMapper.insertUrbUserMdlDtl(vo);
            return vo.getUserMdlNo();
        }
    }

    @Override
    @Transactional
    public int deleteUrbUserMdlDtl(UrbUserMdlDtlVO vo) throws Exception {
        log.warn("Deleting UrbUserMdl (userMdlNo: {})...", vo.getUserMdlNo());
        
        // 1. DB에서 파일 정보를 먼저 조회
        UrbUserMdlDtlVO fileInfo = urbUserMdlDtlMapper.selectUrbUserMdlDtlDetail(vo);
        
        if (fileInfo != null && fileInfo.getFlpth() != null) {
            // 2. 실제 물리적 파일 삭제
            try {
                Files.deleteIfExists(Paths.get(fileInfo.getFlpth()));
                log.info("물리적 파일 삭제 완료: {}", fileInfo.getFlpth());
            } catch (Exception e) {
            	log.warn("사용자 모델 물리 파일 삭제 중 오류 발생");
                log.debug("Physical Delete Failed", e);
            }
        }
        
        // 3. (연관 삭제) 이 모델을 사용하던 "배치" 정보(urb_mdl_mst)도 삭제
        // TODO: urbMdlMstMapper.deleteByUmdNo(vo.getUserMdlNo()) 호출 필요
        
        // 4. DB 레코드 삭제
        urbUserMdlDtlMapper.deleteUrbUserMdlDtl(vo);
        return 1;
    }
}