package incheon.ags.cms.admin.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import incheon.ags.cms.admin.service.CleaningAdminService;
import incheon.ags.cms.admin.mapper.CleaningAdminMapper;
import incheon.ags.cms.admin.vo.CmsCmmnCdVO;
import incheon.ags.cms.admin.vo.RouteVO;
import incheon.ags.cms.admin.vo.VehicleVO;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.egovframe.rte.psl.dataaccess.util.EgovMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service("cleaningAdminService")
@RequiredArgsConstructor
@Transactional
@Slf4j
public class CleaningAdminServiceImpl extends EgovAbstractServiceImpl implements CleaningAdminService {

    private final CleaningAdminMapper cleaningAdminMapper;

    @Override
    public VehicleVO selectVehicleWithRouteList(int vhclId) throws Exception {
        VehicleVO vehicleVO = cleaningAdminMapper.selectVehicleDetailByVhclId(vhclId);
        List<RouteVO> routeList = cleaningAdminMapper.selectRouteListByVhclId(vhclId);
        List<Integer> rteIdList = Optional.ofNullable(routeList)
                                .orElse(Collections.emptyList())
                                .stream()
                                .map(RouteVO::getRteId)
                                .collect(Collectors.toList());

        vehicleVO.setRouteList(routeList);
        vehicleVO.setRteIdList(rteIdList);

        return vehicleVO;
    }

    @Override
    public List<EgovMap> selectVehicleList(VehicleVO vehicleVO) throws Exception {
        return cleaningAdminMapper.selectVehicleList(vehicleVO);
    }

    @Override
    public int selectVehicleTotalCount(VehicleVO vehicleVO) throws Exception {
        return cleaningAdminMapper.selectVehicleTotalCount(vehicleVO);
    }
    @Autowired ObjectMapper objectMapper;
    @Override
    public List<EgovMap> selectRouteList(RouteVO routeVO) throws Exception {

        List<EgovMap> routeList = cleaningAdminMapper.selectRouteList(routeVO);

        routeList.forEach(r -> {
            if (r.get("strGeom") != null) {
                try {
                    r.put("geom", objectMapper.readTree((String) r.get("strGeom")));
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
                r.put("strGeom", null);
            }
        });

        return routeList;
    }

    @Override
    public int selectRouteTotalCount(RouteVO routeVO) throws Exception {
        return cleaningAdminMapper.selectRouteTotalCount(routeVO);
    }

    @Override
    public List<EgovMap> selectSggList() throws Exception {
        return cleaningAdminMapper.selectSggList();
    }

    @Override
    public List<EgovMap> selectControlRuleList() throws Exception {
        return cleaningAdminMapper.selectControlRuleList();
    }

    @Override
    public void validateVehicle(VehicleVO vehicleVO) throws Exception {

        if (vehicleVO.getVhrno() == null || vehicleVO.getVhrno().isBlank()) {
            throw new IllegalArgumentException("차량등록번호가 입력되지 않았습니다");
        }
        if (vehicleVO.getTrmnlTelno() == null || vehicleVO.getTrmnlTelno().isBlank() || vehicleVO.getTrmnlTelno().length() != 11) {
            throw new IllegalArgumentException("잘못된 단말기전화번호입니다. 단말기전화번호: " + vehicleVO.getTrmnlTelno());
        }
        if (vehicleVO.getVin() != null && !vehicleVO.getVin().isBlank() && vehicleVO.getVin().length() != 17) {
            throw new IllegalArgumentException("차대번호는 17자리어야 합니다. 차대번호: " + vehicleVO.getVin());
        }
        if (vehicleVO.getTrmnlUnqIdntfNo() != null && !vehicleVO.getTrmnlUnqIdntfNo().isBlank() && vehicleVO.getTrmnlUnqIdntfNo().length() != 15) {
            throw new IllegalArgumentException("단말기고유번호는 15자리어야 합니다. 단말기고유번호: " + vehicleVO.getTrmnlUnqIdntfNo());
        }

        Map<String, Object> result = null;
        if (0 < vehicleVO.getVhclId()) {
            // 이미 존재하는 차량정보는 자신 제외 검색
            result = cleaningAdminMapper.existVehicleWithoutVhclId(vehicleVO);
        } else {
            result = cleaningAdminMapper.existVehicle(vehicleVO);
        }

        if (Boolean.TRUE.equals(result.get("hasVhrno"))) {
            throw new IllegalStateException("이미 등록된 차량등록번호입니다.");
        }
        if (Boolean.TRUE.equals(result.get("hasTelno"))) {
            throw new IllegalStateException("이미 등록된 단말기전화번호입니다.");
        }
        if (Boolean.TRUE.equals(result.get("hasVin"))) {
            throw new IllegalStateException("이미 등록된 차대번호입니다.");
        }
        if (Boolean.TRUE.equals(result.get("hasImei"))) {
            throw new IllegalStateException("이미 등록된 단말기고유번호입니다.");
        }
    }

    @Override
    public int insertVehicle(VehicleVO vehicleVO) throws Exception {

        this.validateVehicle(vehicleVO);

        int insertVehicleCount = cleaningAdminMapper.insertVehicle(vehicleVO);

        if (insertVehicleCount != 1) {
            throw new IllegalStateException("청소차량 등록 시 문제가 발생했습니다. (insertCount = " + insertVehicleCount + ")");
        }

        if (vehicleVO.getRteIdList() != null && !vehicleVO.getRteIdList().isEmpty()) {
            cleaningAdminMapper.insertVehicleRouteMapping(vehicleVO);
        }
        return insertVehicleCount;
    }

    @Override
    public int updateVehicle(VehicleVO vehicleVO) throws Exception {

        this.validateVehicle(vehicleVO);

        VehicleVO originVehicle = this.selectVehicleWithRouteList(vehicleVO.getVhclId());

        int updateVehicleCount = cleaningAdminMapper.updateVehicle(vehicleVO);

        if (updateVehicleCount != 1) {
            throw new IllegalStateException("청소차량 수정 시 문제가 발생했습니다. (updateCount = " + updateVehicleCount + ")");
        }

        // 노선 매핑 비교
        List<Integer> originRouteList = originVehicle.getRteIdList();
        List<Integer> updateRouteList = vehicleVO.getRteIdList();

        Set<Integer> originRouteSet = new HashSet<>(originRouteList);
        Set<Integer> updateRouteSet = new HashSet<>(updateRouteList);

        // 기존 매핑 노선에서 제거할 노선
        Set<Integer> expireRouteSet = new HashSet<>(originRouteSet);
        expireRouteSet.removeAll(updateRouteSet);

        // 신규 추가할 매핑 노선
        Set<Integer> insertRouteSet = new HashSet<>(updateRouteSet);
        insertRouteSet.removeAll(originRouteSet);

        if (!expireRouteSet.isEmpty()) {
            vehicleVO.setRteIdList(new ArrayList<>(expireRouteSet));
            cleaningAdminMapper.expireVehicleRouteMapping(vehicleVO);
        }

        if (!insertRouteSet.isEmpty()) {
            vehicleVO.setRteIdList(new ArrayList<>(insertRouteSet));
            cleaningAdminMapper.insertVehicleRouteMapping(vehicleVO);
        }

        return updateVehicleCount;
    }

    @Override
    public int disableVehicles(Map<String, Object> paramMap) throws Exception {
        return cleaningAdminMapper.disableVehicles(paramMap);
    }

    @Override
    public int insertRoute(RouteVO routeVO) throws Exception {
        return cleaningAdminMapper.insertRoute(routeVO);
    }

    @Override
    public int updateRoute(RouteVO routeVO) throws Exception {
        return cleaningAdminMapper.updateRoute(routeVO);
    }

    @Override
    public int disableRoutes(Map<String, Object> paramMap) throws Exception {
        return cleaningAdminMapper.disableRoutes(paramMap);
    }

    @Override
    public List<CmsCmmnCdVO> selectCmsCmmnListByGroupCd(String groupCd) throws Exception {
        return cleaningAdminMapper.selectCmsCmmnListByGroupCd(groupCd);
    }

    @Override
    public int insertControlRules(List<Map<String, Object>> rules) throws Exception {
        return cleaningAdminMapper.insertControlRules(rules);
    }

    @Override
    public List<EgovMap> checkRouteMapping(List<Integer> rteIds) throws Exception {
        return cleaningAdminMapper.selectRouteMappingList(rteIds);
    }
}
