package com.its.op.service.its.facility;

import com.its.op.dao.repository.its.cctv.TbCctvCtlrRepository;
import com.its.op.dao.repository.its.facility.TbFcltSttsAlrmStupRepository;
import com.its.op.dao.repository.its.rse.TbRseCtlrRepository;
import com.its.op.dao.repository.its.vds.TbVdsCtlrRepository;
import com.its.op.dao.repository.its.vms.TbVmsCtlrRepository;
import com.its.op.dto.its.facility.TbFcltSttsAlrmStupDto;
import com.its.op.entity.its.cctv.TbCctvCtlr;
import com.its.op.entity.its.facility.TbFcltSttsAlrmStup;
import com.its.op.entity.its.facility.TbFcltSttsAlrmStupKey;
import com.its.op.entity.its.rse.TbRseCtlr;
import com.its.op.entity.its.vds.TbVdsCtlr;
import com.its.op.entity.its.vms.TbVmsCtlr;
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 TbFcltSttsAlrmStupService {

    private final TbFcltSttsAlrmStupRepository repo;
    private final TbCctvCtlrRepository cctvRepo;
    private final TbVmsCtlrRepository vmsRepo;
    private final TbVdsCtlrRepository vdsRepo;
    private final TbRseCtlrRepository rseRepo;


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

    // 전체 데이터 조회
    @Transactional(readOnly = true)
    public List<TbFcltSttsAlrmStupDto> findAllList() {
        Map<String, TbFcltSttsAlrmStupDto> result = new HashMap<>();

        List<TbCctvCtlr> cctvList = this.cctvRepo.findAllList();
        List<TbVmsCtlr> vmsList = this.vmsRepo.findAllList();
        List<TbVdsCtlr> vdsList = this.vdsRepo.findAllList();
        List<TbRseCtlr> rseList = this.rseRepo.findAllList();
        for (TbCctvCtlr cctv : cctvList) {
            result.put(cctv.getCctvCtlrId(), TbFcltSttsAlrmStupDto.build("CCTV", cctv.getCctvCtlrId(), cctv.getCctvNm()));
        }
        for (TbVmsCtlr vms : vmsList) {
            result.put(vms.getVmsCtlrId(), TbFcltSttsAlrmStupDto.build("VMS", vms.getVmsCtlrId(), vms.getVmsNm()));
        }
        for (TbVdsCtlr vds : vdsList) {
            result.put(vds.getVdsCtlrId(), TbFcltSttsAlrmStupDto.build("VDS", vds.getVdsCtlrId(), vds.getVdsNm()));
        }
        for (TbRseCtlr rse : rseList) {
            result.put(rse.getRseCtlrId(), TbFcltSttsAlrmStupDto.build("DSRC", rse.getRseCtlrId(), rse.getRseNm()));
        }

        List<TbFcltSttsAlrmStup> data = this.repo.findAllList();
        for (TbFcltSttsAlrmStup entity : data) {
            TbFcltSttsAlrmStupDto dto = result.get(entity.getFcltId());
            if (dto != null) {
                dto.setInfo(entity);
            }
        }
        return new ArrayList<>(result.values());
    }

    // 데이터 1건 조회(기존 데이터가 반드시 존재해야 함)
    @Transactional(readOnly = true)
    public TbFcltSttsAlrmStupDto findById(TbFcltSttsAlrmStupKey fcltType) {
        TbFcltSttsAlrmStup entity = requireOne(fcltType);
        return entity.toDto();
    }

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

    // 데이터 변경 또는 생성-개별(데이터가 존재하면 업데이트 없으면 신규로 생성)
    @Transactional
    public TbFcltSttsAlrmStupDto mergeInfo(TbFcltSttsAlrmStupDto.TbFcltSttsAlrmStupUpdReq req) {
        TbFcltSttsAlrmStup obj = req.toEntity();
        this.repo.save(obj);
        return obj.toDto();
    }

    /**
     * 시설물 유형별 알람 설정 정보 조회
     * @param fcltType
     * @return
     */
    @Transactional(readOnly = true)
    public List<TbFcltSttsAlrmStupDto> findListById(String fcltType) {
        Map<String, TbFcltSttsAlrmStupDto> result = new HashMap<>();

        if ("CCTV".equals(fcltType)) {
            List<TbCctvCtlr> cctvList = this.cctvRepo.findAllList();
            for (TbCctvCtlr cctv : cctvList) {
                result.put(cctv.getCctvCtlrId(), TbFcltSttsAlrmStupDto.build("CCTV", cctv.getCctvCtlrId(), cctv.getCctvNm()));
            }
        }
        else if ("VMS".equals(fcltType)) {
            List<TbVmsCtlr> vmsList = this.vmsRepo.findAllList();
            for (TbVmsCtlr vms : vmsList) {
                result.put(vms.getVmsCtlrId(), TbFcltSttsAlrmStupDto.build("VMS", vms.getVmsCtlrId(), vms.getVmsNm()));
            }
        }
        else if ("VDS".equals(fcltType)) {
            List<TbVdsCtlr> vdsList = this.vdsRepo.findAllList();
            for (TbVdsCtlr vds : vdsList) {
                result.put(vds.getVdsCtlrId(), TbFcltSttsAlrmStupDto.build("VDS", vds.getVdsCtlrId(), vds.getVdsNm()));
            }
        }
        else if ("DSRC".equals(fcltType)) {
            List<TbRseCtlr> rseList = this.rseRepo.findAllList();
            for (TbRseCtlr rse : rseList) {
                result.put(rse.getRseCtlrId(), TbFcltSttsAlrmStupDto.build("DSRC", rse.getRseCtlrId(), rse.getRseNm()));
            }
        }

        List<TbFcltSttsAlrmStup> data = this.repo.findListById(fcltType);
        for (TbFcltSttsAlrmStup entity : data) {
            TbFcltSttsAlrmStupDto dto = result.get(entity.getFcltId());
            if (dto != null) {
                dto.setInfo(entity);
            }
        }
        return new ArrayList<>(result.values());
    }

    public Map<String, TbFcltSttsAlrmStupDto> loadAlarmSetup(String fcltType) {
        Map<String, TbFcltSttsAlrmStupDto> alarmMap = new HashMap<>();
        List<TbFcltSttsAlrmStup> alarmList = this.repo.findListById(fcltType);
        for (TbFcltSttsAlrmStup entity : alarmList) {
            alarmMap.put(entity.getFcltId(), entity.toDto());
        }
        return alarmMap;
    }

}
