package incheon.uis.gisu.service.impl;

import incheon.uis.gisu.mapper.GisuMapper;
import incheon.uis.gisu.service.GisuService;
import incheon.uis.gisu.vo.GisuDownloadCheckResult;
import incheon.uis.gisu.vo.GisuLayerVO;
import incheon.uis.gisu.vo.GisuUseVO;
import incheon.uis.gisu.vo.TaskLayerVO;
import incheon.uis.ums.shp.ShapeDownloadUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipOutputStream;

@Service
public class GisuServiceImpl implements GisuService {

    private final GisuMapper gisuMapper;
    @Value("${gis.server.url}")
    private String wfsBaseUrl;
    public GisuServiceImpl(GisuMapper gisuMapper) {
        this.gisuMapper = gisuMapper;
    }

    @Override
    public List<GisuUseVO> getMyGisuList(String userUnqId) {
        return gisuMapper.selectMyGisuList(userUnqId);
    }

    @Override
    public Map<String, Object> getMyGisuListWithPaging(String userUnqId, int pageIndex, int pageSize) {
        // offset 계산 (pageIndex는 1부터 시작)
        int offset = (pageIndex - 1) * pageSize;

        // 데이터 조회
        List<GisuUseVO> list = gisuMapper.selectMyGisuListWithPaging(userUnqId, pageSize, offset);

        // 전체 개수 조회
        int totalCount = gisuMapper.selectMyGisuListTotalCount(userUnqId);

        // 다음 페이지 존재 여부
        boolean hasNext = (pageIndex * pageSize) < totalCount;

        // 결과 반환
        Map<String, Object> result = new HashMap<>();
        result.put("list", list);
        result.put("totalCount", totalCount);
        result.put("hasNext", hasNext);

        return result;
    }

    @Override
    public List<TaskLayerVO> getAvailableTaskLayers() {
        return gisuMapper.selectAvailableTaskLayers();
    }

    @Override
    @Transactional
    public Long registerGisu(String userUnqId, String usePurps, List<String> taskLyrList) {
        if (taskLyrList == null || taskLyrList.isEmpty()) {
            throw new IllegalArgumentException("신청 대상 레이어를 한 개 이상 선택해야 합니다.");
        }

        GisuUseVO vo = new GisuUseVO();
        vo.setUserUnqId(userUnqId);
        vo.setUsePurps(usePurps);
        vo.setPrcsStts("TRS001"); // 신청 상태

        // 1) 마스터 저장 → useGeneratedKeys 로 vo.idn 채워짐
        gisuMapper.insertGisuUse(vo);

        Long gisuIdn = vo.getIdn();  // <-- 이 값이 prnt_idn 으로 들어감

        // 2) 디테일(레이어) 저장
        gisuMapper.insertGisuLayers(gisuIdn, taskLyrList);

        return gisuIdn;
    }

    @Override
    @Transactional(readOnly = true)
    public Path createZipForApprovedGisu(Long idn, String userUnqId) {

        // 0) 비즈니스 체크 공통 사용
        GisuDownloadCheckResult chk = checkDownloadAvailable(idn, userUnqId);
        if (!chk.isSuccess()) {
            // 이 메서드는 파일 스트림 전용이니까 여기서는 예외로 던져도 됨
            throw new IllegalStateException(chk.getMessage());
        }

        // 2) 레이어 목록 조회 (체크에서 이미 봤지만 다시 가져옴)
        List<GisuLayerVO> layers = gisuMapper.selectGisuLayers(idn);

        try {
            // 3) 임시 디렉토리
            Path tmpDir = Files.createTempDirectory("gisu_" + idn + "_");

            // 4) ZIP 파일 경로
            String ts = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
            String zipFileName = "gisu_" + idn + "_" + ts + ".zip";
            Path zipPath = tmpDir.resolve(zipFileName);

            // 5) 바깥 ZIP 생성 + 유틸 사용
            try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(zipPath))) {

                for (GisuLayerVO lyr : layers) {
                    String typeName = lyr.getTaskLyr();
                    if (typeName == null || typeName.isBlank())
                        continue;

                    ShapeDownloadUtil.addLayerFromWfs(
                            zos,
                            wfsBaseUrl,
                            typeName,
                            null   // cqlFilter 필요 시 여기 세팅
                    );
                }
            }

            return zipPath;

        } catch (IOException e) {
            // 이건 시스템 오류라 그대로 예외
            throw new RuntimeException("ZIP 생성 중 오류 발생", e);
        }
    }


    @Override
    @Transactional(readOnly = true)
    public GisuDownloadCheckResult checkDownloadAvailable(Long idn, String userUnqId) {

        GisuDownloadCheckResult result = new GisuDownloadCheckResult();

        // 1) 승인 상태 + 본인 건인지 확인
        GisuUseVO gisu = gisuMapper.selectApprovedGisuForUser(idn, userUnqId);
        if (gisu == null) {
            result.setSuccess(false);
            result.setMessage("승인된 신청건이 아니거나 권한이 없습니다.");
            return result;
        }

        // 2) 승인일(= last_mdfcn_dt) 기준 7일 이내 체크
        LocalDateTime approvedAt = gisu.getLastMdfcnDt();
        if (approvedAt == null) {
            result.setSuccess(false);
            result.setMessage("승인일 정보가 없어 다운로드할 수 없습니다. 관리자에게 문의하세요.");
            return result;
        }

        if (approvedAt.isBefore(LocalDateTime.now().minusDays(7))) {
            result.setSuccess(false);
            result.setMessage("승인일로부터 7일이 경과하여 다운로드할 수 없습니다.");
            return result;
        }

        // 3) 레이어 목록 존재 여부 체크
        List<GisuLayerVO> layers = gisuMapper.selectGisuLayers(idn);
        if (layers == null || layers.isEmpty()) {
            result.setSuccess(false);
            result.setMessage("신청된 레이어가 없습니다.");
            return result;
        }

        result.setSuccess(true);
        result.setMessage("다운로드 가능합니다.");
        return result;
    }

    @Override
    public List<TaskLayerVO> getGisuLayers(Long idn) {
        if (idn == null) {
            throw new IllegalArgumentException("신청번호(idn)는 필수입니다.");
        }
        return gisuMapper.selectGisuLayersList(idn);
    }


}
