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

import com.its.op.dao.repository.its.vms.TbVmsCtlrRepository;
import com.its.op.dao.repository.its.vms.TbVmsDsplPrstRepository;
import com.its.op.dto.its.vms.TbVmsDsplPrstDto;
import com.its.op.entity.its.vms.TbVmsCtlr;
import com.its.op.entity.its.vms.TbVmsDsplPrst;
import com.its.op.entity.its.vms.TbVmsDsplPrstKey;
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 TbVmsDsplPrstService {

    private final TbVmsDsplPrstRepository repo;
    private final TbVmsCtlrRepository ctlrRepo;

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

    /**
     * 현재 표출 VMS 메시지 전체 조회
     * @return
     */
    @Transactional(readOnly = true)
    public List<TbVmsDsplPrstDto> findAll() {
        List<TbVmsDsplPrstDto> result = new ArrayList<>();
        List<TbVmsDsplPrst> data = this.repo.findAll();
        List<TbVmsCtlr> stts = this.ctlrRepo.findAllList();
        return makeDsplPrstList(data, stts);
//        for (TbVmsDsplPrst entity : data) {
//            result.add(entity.toDto());
//        }
//        return result;
    }

    /**
     * 현재 표출 VMS 메시지 개별 조회
     * @return
     */
    @Transactional(readOnly = true)
    public List<TbVmsDsplPrstDto> findAllByIds(List<Long> ids) {
        List<TbVmsDsplPrstDto> result = new ArrayList<>();
        List<TbVmsDsplPrst> data = this.repo.findAllByIds(ids);
        List<TbVmsCtlr> stts = this.ctlrRepo.findAllListByIds(ids);
        return makeDsplPrstList(data, stts);
//        for (TbVmsDsplPrst entity : data) {
//            result.add(entity.toDto());
//        }
//        return result;
    }

    /**
     * VMS 표출 메시지 DTO 목록 생성
     * @param data
     * @param vmsList
     * @return
     */
    public List<TbVmsDsplPrstDto> makeDsplPrstList(List<TbVmsDsplPrst> data, List<TbVmsCtlr> vmsList) {
        Map<Long, TbVmsDsplPrstDto> result = new HashMap<>();
        data.forEach(obj -> {
            TbVmsDsplPrstDto dto = result.get(obj.getVmsCtlrNmbr());
            if (dto == null) {
                dto = obj.toDto();
                result.put(obj.getVmsCtlrNmbr(), dto);
            }
            dto.addMsg(obj);
        });
        vmsList.forEach(obj -> {
            TbVmsDsplPrstDto dto = result.get(obj.getVmsCtlrNmbr());
            if (dto != null) {
                dto.setStts(obj);
            }
        });
        return new ArrayList<>(result.values());
    }

    /**
     * VMS 표출 메시지 DTO 생성
     * @param data
     * @param vms
     * @return
     */
    public TbVmsDsplPrstDto makeDsplPrst(TbVmsDsplPrst data, TbVmsCtlr vms) {
        TbVmsDsplPrstDto result = data.toDto();
        result.addMsg(data);
        result.setStts(vms);
        return result;
    }

    // 데이터 1건 조회(기존 데이터가 반드시 존재해야 함)
    @Transactional(readOnly = true)
    public TbVmsDsplPrstDto findById(TbVmsDsplPrstKey id) {
        TbVmsDsplPrst data = requireOne(id);
        Optional<TbVmsCtlr> stts = this.ctlrRepo.findById(id.getVmsCtlrNmbr());
        if (stts.isPresent()) {
            return makeDsplPrst(data, stts.get());
        }
        return makeDsplPrst(data, null);
    }

    /**
     * 관리번호, 표출번호에 해당하는 메시지 조회
     * @param vmsCtlrNmbr
     * @param phase
     * @return
     */
    //@Transactional(readOnly = true)
    public TbVmsDsplPrstDto findAllByIdAndPhase(Long vmsCtlrNmbr, Integer phase) {
        TbVmsDsplPrstKey key = new TbVmsDsplPrstKey(vmsCtlrNmbr, phase);
        //TbVmsDsplPrst data = requireOne(key);
        return findById(key);
    }
}
