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

import com.its.op.dao.repository.its.vms.TbVmsDsplSchRepository;
import com.its.op.dao.repository.its.vms.TbVmsFormObjectRepository;
import com.its.op.dao.repository.its.vms.TbVmsFormRepository;
import com.its.op.dto.its.common.NewIdIntegerDto;
import com.its.op.dto.its.common.UsageCountDto;
import com.its.op.dto.its.vms.*;
import com.its.op.entity.its.vms.TbVmsForm;
import com.its.op.entity.its.vms.TbVmsFormObject;
import com.its.op.entity.its.vms.TbVmsFormObjectDetlInf;
import com.its.op.entity.its.vms.TbVmsFormSimple;
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 TbVmsFormService {

    private final TbVmsFormRepository repo;
    private final TbVmsFormObjectRepository objectRepo;
    private final TbVmsDsplSchRepository scheduleRepo;

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

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

    /**
     * VMS TYPE(크기) 에 해당되는 폼 정보를 조회한다.
     * @param vmsTypeCd
     * @return
     */
    @Transactional(readOnly = true)
    public List<TbVmsFormDto> findAllByVmsType(String vmsTypeCd) {
        List<TbVmsFormDto> result = new ArrayList<>();
        List<TbVmsForm> data = this.repo.findAllByVmsType(vmsTypeCd);
        for (TbVmsForm entity : data) {
            TbVmsFormDto dto = entity.toDto();
//            dto.setVmsFormImag(ItsUtils.convertBmpToPng(dto.getVmsFormImag()));
//            dto.setImagFmt("png");
            result.add(dto);
        }
        return result;
    }

    /**
     * VMS TYPE(크기) 및 폼 유형에 해당되는 폼 정보를 조회한다.
     * @param vmsTypeCd
     * @param formTypeCd
     * @return
     */
    @Transactional(readOnly = true)
    public List<TbVmsFormDto> findAllByVmsTypeAndFormType(String vmsTypeCd, List<Integer> formTypeCd) {
        List<TbVmsFormDto> result = new ArrayList<>();
        List<TbVmsForm> data = this.repo.findAllByVmsTypeAndFormType(vmsTypeCd, formTypeCd);
        for (TbVmsForm entity : data) {
            TbVmsFormDto dto = entity.toDto();
//            dto.setVmsFormImag(ItsUtils.convertBmpToPng(dto.getVmsFormImag()));
//            dto.setImagFmt("png");
            result.add(dto);
        }
        return result;
    }
    // 교통정보
    public List<TbVmsFormDto> findAllTraffic(String vmsTypeCd) {
        List<Integer> formTypeCd = Arrays.asList(11, 12, 13, 14, 15);
        return findAllByVmsTypeAndFormType(vmsTypeCd, formTypeCd);
    }
    // 정체
    public List<TbVmsFormDto> findAllCongest(String vmsTypeCd) {
        List<Integer> formTypeCd = Arrays.asList(16);
        return findAllByVmsTypeAndFormType(vmsTypeCd, formTypeCd);
    }
    // 돌발
    public List<TbVmsFormDto> findAllIncident(String vmsTypeCd) {
        List<Integer> formTypeCd = Arrays.asList(20);
        return findAllByVmsTypeAndFormType(vmsTypeCd, formTypeCd);
    }
    // 공사/행사
    public List<TbVmsFormDto> findAllEvent(String vmsTypeCd) {
        List<Integer> formTypeCd = Arrays.asList(30);
        return findAllByVmsTypeAndFormType(vmsTypeCd, formTypeCd);
    }
    // 홍보
    public List<TbVmsFormDto> findAllHongbo(String vmsTypeCd) {
        List<Integer> formTypeCd = Arrays.asList(40);
        return findAllByVmsTypeAndFormType(vmsTypeCd, formTypeCd);
    }
    // 우회도로
    public List<TbVmsFormDto> findAllDetour(String vmsTypeCd) {
        List<Integer> formTypeCd = Arrays.asList(50);
        return findAllByVmsTypeAndFormType(vmsTypeCd, formTypeCd);
    }
    // 재난안전
    public List<TbVmsFormDto> findAllSafety(String vmsTypeCd) {
        List<Integer> formTypeCd = Arrays.asList(60);
        return findAllByVmsTypeAndFormType(vmsTypeCd, formTypeCd);
    }

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

    /**
     * 폼 정보 만 업데이트 한다
     * @param id
     * @param req
     * @return
     */
    @Transactional
    public TbVmsFormDto updateById(Integer id, TbVmsFormDto.TbVmsFormUpdReq req) {
        TbVmsForm entity = requireOne(id);
        entity.updateInfo(req);
        this.repo.save(entity);
        return entity.toDto();
    }

    /**
     * 데이터 변경 또는 생성-개별(데이터가 존재하면 업데이트 없으면 신규로 생성)
     * 폼 정보를 저장한 후 폼 객체 정보를 삭제한 다음 폼 객체 정보를 저장한다.
     * @param req
     * @return
     */
    @Transactional
    public TbVmsFormDto mergeInfo(TbVmsFormDto.TbVmsFormUpdReq req) {
        TbVmsForm obj = req.toEntity();
        // 폼 정보를 삭제한다.
        this.repo.save(obj);
        // 폼 객체 정보를 삭제한다.
        this.objectRepo.deleteDataById(req.getVmsFormId());
        // 폼 객체 정보를 저장한다.
        List<TbVmsFormObjectDto.TbVmsFormObjectUpdReq> objects = req.getObjects();
        if (objects != null) {
            objects.forEach(formObjectDto -> {
                TbVmsFormObject object = formObjectDto.toEntity();
                this.objectRepo.save(object);
            });
        }
        return obj.toDto();
    }

    /**
     * 폼 정보를 삭제한다.
     * @param vmsFormId
     * @return
     */
    @Transactional
    public TbVmsFormDto deleteById(Integer vmsFormId) {
        TbVmsForm entity = requireOne(vmsFormId);
        // 폼 객체 정보를 먼저 삭제한다.
        this.objectRepo.deleteDataById(vmsFormId);
        // 폼 정보를 삭제한다.
        this.repo.deleteById(vmsFormId);
        return entity.toDto();
    }

    /**
     * VMS 폼의 객체 정보 목록을 조회한다.
     * @param vmsFormId
     * @return
     */
    @Transactional(readOnly = true)
    public List<TbVmsFormObjectDetlDto> findByVmsFormObject(Integer vmsFormId) {
        List<TbVmsFormObjectDetlDto> result = new ArrayList<>();
        List<TbVmsFormObjectDetlInf> data = this.repo.findByVmsFormObject(vmsFormId);
        data.forEach(obj -> {
            TbVmsFormObjectDetlDto dto = TbVmsFormObjectDetlDto.builder()
                    .formObjectId(obj.getVmsFormObjectId())
                    .vmsFormId(obj.getVmsFormId())
                    .vmsFormDsplRow(obj.getVmsFormDsplRow())
                    .vmsFormDsplClmn(obj.getVmsFormDsplClmn())
                    .vmsFormObjectTypeCd(obj.getVmsFormObjectTypeCd())
                    .vmsFontNameCd(obj.getVmsFontNameCd())
                    .vmsFontColrCd(obj.getVmsFontColrCd())
                    .vmsFontBold(obj.getVmsFontBold())
                    .vmsFontSize(obj.getVmsFontSize())
                    .vmsFontAlign(obj.getVmsFontAlign())
                    .vmsDsplTxt(obj.getVmsDsplTxt())
                    .vmsDsplFigr(obj.getVmsDsplFigr())
                    .vmsDsplXcrdn(obj.getVmsDsplXcrdn())
                    .vmsDsplYcrdn(obj.getVmsDsplYcrdn())
                    .vmsDsplWidth(obj.getVmsDsplWidth())
                    .vmsDsplHeight(obj.getVmsDsplHeight())
                    .vmsDsplBlinking(obj.getVmsDsplBlinking())
                    .vmsDsplBkcolor(obj.getVmsDsplBkcolor())
                    .vmsDsplSize(obj.getVmsDsplSize())
                    .trfcFillCd(obj.getTrfcFillCd())
                    .symbLibNmbr(obj.getSymbLibNmbr())
                    .vmsIfscId(obj.getVmsIfscId())
                    .vmsFontName(obj.getVmsFontName())
                    .imagData(obj.getImagData())
                    .symbExpl(obj.getSymbExpl())
                    .vmsTypeCd(obj.getVmsTypeCd())
                    .vmsFormTypeCd(obj.getVmsFormTypeCd())
                    .vmsFormColrCd(obj.getVmsFormColrCd())
                    .vmsFormNm(obj.getVmsFormNm())
                    .build();

            result.add(dto);
        });
        return result;
    }

    /**
     * 신규 VMS FORM ID 조회
     * @return
     */
    @Transactional(readOnly = true)
    public NewIdIntegerDto getNewVmsFormId() {
        Integer newId = this.repo.getNewVmsFormId();
        NewIdIntegerDto result = NewIdIntegerDto.builder()
                .newId(newId)
                .build();
        return result;
    }

    /**
     * VMS 크기 유형별 폼 목록 조회
     * @param type
     * @return
     */
    @Transactional(readOnly = true)
    public List<TbVmsFormDto> findAllByTypeSimple(String type) {
        List<TbVmsFormDto> result = new ArrayList<>();
        List<TbVmsFormSimple> data = this.repo.findAllByVmsTypeSimple(type);

        Map<Integer, TbVmsFormDsplTxtDto> tmp = new HashMap<>();
        List<TbVmsFormDsplTxtInf> dsplTxtList = this.repo.findAllByVmsTypeFormDsplTxt(type);
        for (TbVmsFormDsplTxtInf txt : dsplTxtList) {
            tmp.put(txt.getVmsFormId().intValue(),
                    TbVmsFormDsplTxtDto.builder()
                            .vmsFormId(txt.getVmsFormId().intValue())
                            .vmsDsplTxt(txt.getVmsDsplTxt())
                            .build());
        }

        for (TbVmsFormSimple entity : data) {
            TbVmsFormDto dto = entity.toDto();
            TbVmsFormDsplTxtDto dtoTxt = tmp.get(dto.getVmsFormId());
            if (dtoTxt != null) {
                dto.setVmsDsplTxt(dtoTxt.getVmsDsplTxt());
            }
            result.add(dto);
        }
        return result;
    }

    /**
     * VMS 폼 정보 상세 조회(이미지, 객체 목록 포함)
     * @param vmsFormId
     * @return
     */
//    @Transactional(readOnly = true)
    public TbVmsFormDetlDto findByVmsFormObjectDetail(Integer vmsFormId) {
        return TbVmsFormDetlDto.builder()
                .form(findById(vmsFormId))
                .objects(findByVmsFormObject(vmsFormId))
                .build();
    }

    /**
     * VMS 폼 복사 추가
     * @param req
     * @return
     */
    //@Transactional
    public TbVmsFormDto formCopyAdd(TbVmsFormDto.TbVmsFormCopyReq req) {
        TbVmsForm orgForm = requireOne(req.getVmsFormId());
        NewIdIntegerDto newFormId = getNewVmsFormId();
        // 폼 정보 복사 해서 추가
        this.repo.copyForm(newFormId.getNewId(), req.getVmsFormId(), req.getVmsFormNm());
        // 폼 객체 정보 복사해서 추가
        this.objectRepo.copyFormObjects(newFormId.getNewId(), req.getVmsFormId());

        orgForm.copyForm(newFormId.getNewId(), req.getVmsFormNm());
        return orgForm.toDto();
    }

    public UsageCountDto findUsageId(Integer id) {
        UsageCountDto result = UsageCountDto.builder()
                .count(0)
                .build();
        Integer data = this.scheduleRepo.findUsageCountByFormId(id);
        result.setCount(data);
        return result;
    }
}
