package com.its.op.service.its.vms;

import com.its.op.dao.repository.its.vms.TbVmsIfscRepository;
import com.its.op.dto.its.common.NewIdLongDto;
import com.its.op.dto.its.common.UsageCountDto;
import com.its.op.dto.its.vms.TbVmsIfscCmtrGradDto;
import com.its.op.dto.its.vms.TbVmsIfscDto;
import com.its.op.dto.its.vms.TbVmsIfscRltnIfscDto;
import com.its.op.entity.its.vms.TbVmsIfsc;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Slf4j
@RequiredArgsConstructor
@Service
public class TbVmsIfscService {

    private final TbVmsIfscRepository repo;
    private final TbVmsRltnIfscService ifscRltnService;
    private final TbVmsFormObjectService formObjectService;
    private final TbVmsIfscRltnIfscService linkIfscService;
    private final TbVmsIfscCmtrGradService cmtrGradService;
    private final TbVmsIfscTrafService vmsIfscTrafService;

    // 데이터 1건 조회, 없으면 exception
    private TbVmsIfsc requireOne(Long id) throws NoSuchElementException {
        Optional<TbVmsIfsc> info = this.repo.findById(id);
        if (info.isPresent()) {
            return info.get();
        }
        else {
            throw new NoSuchElementException("데이터가 존재하지 않습니다: " + id);
        }
//        return repo.findById(id)
//                .orElseThrow(() -> new NoSuchElementException("데이터가 존재하지 않습니다: " + id));
    }

    // 전체 데이터 조회
    public List<TbVmsIfscDto> findAll() {
        List<TbVmsIfscDto> result = new ArrayList<>();
        List<TbVmsIfsc> data = this.repo.findAll();
        for (TbVmsIfsc entity : data) {
            result.add(entity.toDto());
        }
        return result;
    }

    // 데이터 1건 조회(기존 데이터가 반드시 존재해야 함)
    public TbVmsIfscDto findById(Long id) {
        // VMS 정보제공구간 조회
        TbVmsIfsc entity = requireOne(id);
        // 정보제공구간 구성정보 조회
        List<TbVmsIfscRltnIfscDto> list = this.linkIfscService.findDataById(id);
        TbVmsIfscDto dto = entity.toDto();
        dto.setIfscs(list);

        TbVmsIfscCmtrGradDto.CmtrGrad grad1 = new TbVmsIfscCmtrGradDto.CmtrGrad(0, 0);
        TbVmsIfscCmtrGradDto.CmtrGrad grad2 = new TbVmsIfscCmtrGradDto.CmtrGrad(0, 0);
        TbVmsIfscCmtrGradDto.CmtrGrad grad3 = new TbVmsIfscCmtrGradDto.CmtrGrad(0, 0);
        // 정보제공구간 소통등급 정보 조회
        List<TbVmsIfscCmtrGradDto> gradList = this.cmtrGradService.findDataById(id);
        if (gradList != null) {
            for (TbVmsIfscCmtrGradDto grad : gradList) {
                if (("1").equals(grad.getCmtrGradCd())) {
                    grad1.setHghssped(grad.getHghssped());
                    grad1.setLwstsped(grad.getLwstsped());
                }
                else if (("2").equals(grad.getCmtrGradCd())) {
                    grad2.setHghssped(grad.getHghssped());
                    grad2.setLwstsped(grad.getLwstsped());
                }
                else if (("3").equals(grad.getCmtrGradCd())) {
                    grad3.setHghssped(grad.getHghssped());
                    grad3.setLwstsped(grad.getLwstsped());
                }
            }
        }
        dto.setGrad1(grad1);
        dto.setGrad2(grad2);
        dto.setGrad3(grad3);

        return dto;
    }

    // 데이터 변경
    public TbVmsIfscDto updateById(Long id, TbVmsIfscDto.TbVmsIfscUpdReq req) {
        TbVmsIfsc entity = requireOne(id);
        entity.updateInfo(req);
        this.repo.save(entity);
        return entity.toDto();
    }

    // 데이터 변경 또는 생성-목록(데이터가 존재하면 업데이트 없으면 신규로 생성)
    public List<TbVmsIfscDto> mergeInfoList(List<TbVmsIfscDto.TbVmsIfscUpdReq> reqList) {
        List<TbVmsIfscDto> result = new ArrayList<>();
        for (TbVmsIfscDto.TbVmsIfscUpdReq req : reqList) {
            TbVmsIfsc obj = req.toEntity();
            this.repo.save(obj);
            result.add(obj.toDto());
        }
        return result;
    }

    // 데이터 변경 또는 생성-개별(데이터가 존재하면 업데이트 없으면 신규로 생성)
    @Transactional
    public TbVmsIfscDto.TbVmsIfscUpdReq mergeInfo(TbVmsIfscDto.TbVmsIfscUpdReq req) {

        if (req.getDetrId() == 0) {
            req.setDetrId(null);
        }

        // VMS 정보제공구간 정보 저장
        if (req.getUseYn() == null) {
            req.setUseYn("Y");  // 사용여부
        }
        TbVmsIfsc obj = req.toEntity();
        this.repo.save(obj);

        // 소통등급 정보 저장(merge)
        TbVmsIfscCmtrGradDto.TbVmsIfscCmtrGradUpdReq grad1 = new TbVmsIfscCmtrGradDto.TbVmsIfscCmtrGradUpdReq(req.getVmsIfscId(), "1", req.getGrad1().getLwstsped(), req.getGrad1().getHghssped());
        TbVmsIfscCmtrGradDto.TbVmsIfscCmtrGradUpdReq grad2 = new TbVmsIfscCmtrGradDto.TbVmsIfscCmtrGradUpdReq(req.getVmsIfscId(), "2", req.getGrad2().getLwstsped(), req.getGrad2().getHghssped());
        TbVmsIfscCmtrGradDto.TbVmsIfscCmtrGradUpdReq grad3 = new TbVmsIfscCmtrGradDto.TbVmsIfscCmtrGradUpdReq(req.getVmsIfscId(), "3", req.getGrad3().getLwstsped(), req.getGrad3().getHghssped());
        this.cmtrGradService.mergeInfo(grad1);
        this.cmtrGradService.mergeInfo(grad2);
        this.cmtrGradService.mergeInfo(grad3);

        // VMS LINK 정보제공구간 정보 삭제
        this.linkIfscService.deleteDataById(req.getVmsIfscId());
        // VMS LINK 정보제공구간 정보 저장
        for (TbVmsIfscDto.VmsIfscLinkOrd ifsc : req.getIfscs()) {
            TbVmsIfscRltnIfscDto.TbVmsLinkIfscUpdReq ifscReq = new TbVmsIfscRltnIfscDto.TbVmsLinkIfscUpdReq(req.getVmsIfscId(), ifsc.getIfscId(), ifsc.getOrd());
            TbVmsIfscRltnIfscDto ifscDto = this.linkIfscService.mergeInfo(ifscReq);
        }

        return req;
    }

    // 정보 삭제-개별, 데이터 존재하지 않으면 Exception
    @Transactional
    public TbVmsIfscDto deleteById(Long id) throws ConcurrentModificationException {
        UsageCountDto usageCount = findUsageCountByVmsIfscId(id);
        if (usageCount.getCount() > 0) {
            throw new ConcurrentModificationException("사용중인 정보제공구간 입니다. 삭제할 수 없습니다: " + id);
        }

        //VMS_정보제공구간 소통 등급
        //sQry = "DELETE FROM TB_VMS_IFSC_CMTR_GRAD WHERE VMS_IFSC_ID = :p01";

        //VMS LINK 정보제공구간
        //sQry = "DELETE FROM TB_VMS_LINK_IFSC WHERE VMS_IFSC_ID = :p01";

        //VMS 정보제공구간 관계
        //sQry = "DELETE FROM TB_VMS_IFSC_RLTN WHERE VMS_IFSC_ID = :p01";

        //VMS_소통정보
        //sQry = "DELETE FROM TB_VMS_CMTRINFR WHERE VMS_IFSC_ID = :p01";

        //VMS_정보제공구간
        //#if 1
        //        sQry = "DELETE FROM TB_VMS_IFSC WHERE VMS_IFSC_ID = :p01";
        //#else
        //        sQry = "UPDATE TB_VMS_IFSC SET EDTN_CD = 'EDI2' WHERE VMS_IFSC_ID = :p01";
        //#endif

        TbVmsIfsc entity = requireOne(id);

        // VMS 정보제공구간 소통등급 정보 삭제
        this.cmtrGradService.deleteDataById(id);

        // VMS LINK 정보제공구간에 속하는 정보제공구간 정보 목록 삭제
        this.linkIfscService.deleteDataById(id);

        // VMS 정보제공구간 소통정보 테이블 삭제
        this.vmsIfscTrafService.deleteDataById(id);

        // VMS 정보제공구간 정보 삭제
        this.repo.deleteById(id);

        return entity.toDto();
    }

    // 정보 삭제-목록, 존재하는 데이터 만 삭제
    public List<TbVmsIfscDto> deleteByIds(List<Long> ids) {
        List<TbVmsIfscDto> result = new ArrayList<>();
        for (Long id : ids) {
            result.add(deleteById(id));
        }
        return result;
    }

    // VMS 정보 제공구간이 사용되는 갯수 리턴
    @Transactional(readOnly = true)
    public UsageCountDto findUsageCountByVmsIfscId(Long vmsIfscId) {
        UsageCountDto result = UsageCountDto.builder()
                .count(0)
                .build();
        Integer useCount = 0;

        // TB_VMS_IFSC(VMS 정보제공구간), DETR_ID 에 설정되어 사용 중인지 확인.
        useCount = this.repo.findUsageCountByVmsIfscId(vmsIfscId);
        log.info("Usage TB_VMS_IFSC.DETR_ID: {}", useCount);
        if (useCount > 0) {
            result.setCount(1);
            return result;
        }

        // TB_VMS_IFSC_RLTN(VMS 정보제공구간 관계) 설정 테이블에 사용 중인지 확인
        useCount = useCount + this.ifscRltnService.findUsageCountByVmsIfscId(vmsIfscId);
        log.info("Usage TB_VMS_IFSC_RLTN.VMS_IFSC_ID: {}", useCount);
        if (useCount > 0) {
            result.setCount(2);
            return result;
        }

        // TB_VMS_FORM_OBJECT(VMS FORM OBJECT) 설정 테이블에 사용 중인지 확인
        useCount = this.formObjectService.findUsageCountByVmsIfscId(vmsIfscId);
        log.info("Usage TB_VMS_FORM_OBJECT.VMS_IFSC_ID: {}", useCount);
        if (useCount > 0) {
            result.setCount(3);
            return result;
        }

        return result;
    }

    /**
     * VMS 정보제공구간 신규 ID 조회
     * @return
     */
    @Transactional(readOnly = true)
    public NewIdLongDto getNewVmsIfscId() {
        Long newId = this.repo.getNewVmsIfscId();
        return NewIdLongDto.builder().newId(newId).build();
    }
}
