package com.its.vms.service;

import com.its.app.utils.FloodFill;
import com.its.app.utils.ItsUtils;
import com.its.vms.config.ApplicationConfig;
import com.its.vms.dao.mapper.VmsSymbMapper;
import com.its.vms.dto.TbVmsSymbIfscDto;
import com.its.vms.dto.TbVmsSymbLibDto;
import com.its.vms.entity.TbVmsSymbIfsc;
import com.its.vms.entity.TbVmsSymbLib;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
@RequiredArgsConstructor
public class VmsSymbService {

    private final ApplicationConfig config;
    private final VmsSymbMapper vmsSymbMapper;

    public ConcurrentHashMap<String, TbVmsSymbLib> symbMap = new ConcurrentHashMap<>();

    public void loadVmsSymbInfo() {
        loadVmsSymbLib();
        loadVmsSymbCellInfo();
    }

    public void loadVmsSymbLib() {
        try {
            List<TbVmsSymbLibDto> infoList  = this.vmsSymbMapper.selectVmsSymbLib();
            log.info("VmsSymbService.loadVmsSymbLib(), {} EA", infoList.size());
            infoList.forEach(dto -> {
                // 심벌 유형(SBT0:일반심벌이미지,SBT1:소통정보배경,SBT2:소통정보이미지,SBT3:동영상,SBT4:대기환경등급)
                // 소통정보이미지 때문에 이미지번호에 "0" 을 추가하여 이미지번호로 사용함
                String updtDt = "";
                TbVmsSymbLib obj = dto.toEntity();
                TbVmsSymbLib oldObj = this.symbMap.get(obj.getSymbLibNmbr());
                if (oldObj != null) {
                    updtDt = oldObj.getUpdtDt();
                }
                this.symbMap.put(obj.getSymbLibNmbr(), obj);

                if ("SBT4".equals(obj.getSymbType())) {
                    // 대기환경등급
                    String symbExpl = dto.getSymbExpl();
                    if (symbExpl != null) {
                        String[] symbNmbrArr = symbExpl.split("\\^");
                        for (String symbNmbr : symbNmbrArr) {
                            obj.getGradSymbLibNmbrList().add(symbNmbr + "0");
                        }
                    }
                }

                obj.setLocalFileName(this.config.getFtpImageDir() + obj.getSymbFileNm());
                obj.setFtpFileName(ApplicationConfig.FTP_IMAGE + File.separator + obj.getSymbFileNm()); // Ftp 다운로드 명을 설정

                // 심벌 유형(SBT0:일반심벌이미지,SBT1:소통정보배경,SBT2:소통정보이미지,SBT3:동영상)
                if ("SBT3".equals(obj.getSymbType())) {
                    //위에서 이미지저장하기 위해 파일명을 변경하기 때문에 여기서 동영상 파일명을 다시 읽어온다
                    obj.setSymbFileNm(dto.getSymbFileNm()); //동영상인 경우 동영상 파일명
                    obj.setLocalFileName(this.config.getFtpVideoDir() + obj.getSymbFileNm());
                    obj.setFtpFileName(ApplicationConfig.FTP_VIDEO + File.separator + obj.getSymbFileNm()); // Ftp 다운로드 명을 설정
                }

                if ("SBT2".equals(obj.getSymbType())) {
                    //심벌 유형(SBT0:일반심벌이미지,SBT1:소통정보배경,SBT2:소통정보이미지,SBT3:동영상)
                    //소통정보 등급에 따른 이미지를 새롭게 추가한다.
                    for (int nTrf = 1; nTrf <= 3; nTrf++) {
                        String trfUpdtDt = "";
                        String trafSymbLibNmbr = dto.getSymbLibNmbr() + String.valueOf(nTrf);
                        TbVmsSymbLib trfObj = this.symbMap.get(trafSymbLibNmbr);
                        if (trfObj != null) {
                            trfUpdtDt = trfObj.getUpdtDt();
                        }
                        trfObj = obj.clone(trafSymbLibNmbr);

                        this.symbMap.put(trfObj.getSymbLibNmbr(), trfObj);

                        Image imgBmp = obj.getImage();  // 원천이미지를 가지고 온다.
                        if (imgBmp == null) {
                            log.error("VmsSymbService.loadVmsSymbLib: Image Data Error: {}", trafSymbLibNmbr);
                            continue;
                        }

                        String imagFmt = "bmp";
                        BufferedImage formImage = new BufferedImage(imgBmp.getWidth(null), imgBmp.getHeight(null),
                                (("png").equals(imagFmt) ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB));
                        Graphics2D 	g2d = (Graphics2D)formImage.createGraphics();

                        FloodFill floodFill = new FloodFill(imgBmp);
                        floodFill.setAntialiased(false);
                        int orgColor = floodFill.getImage().getRGB(obj.getPosX(), obj.getPosY());
                        int trfColor = VmsSymbService.getGradColor(nTrf);
                        if (orgColor != trfColor) {
                            floodFill.fill(obj.getPosX(), obj.getPosY(), VmsSymbService.getTrafColor(nTrf));
                        }
                        g2d.drawImage(floodFill.getImage(), 0, 0, imgBmp.getWidth(null), imgBmp.getHeight(null), null);
                        ByteArrayOutputStream out = new ByteArrayOutputStream();
                        try {
                            ImageIO.write(formImage, imagFmt, out);
                        } catch (IOException e) {
                            log.error("VmsSymbService.loadVmsSymbLib: Image Convert error: {}", trafSymbLibNmbr);
                        }
                        g2d.dispose();
                        trfObj.setImagData(out.toByteArray());

                        trfObj.setLocalFileName(this.config.getFtpImageDir() + trfObj.getSymbFileNm());
                        trfObj.setFtpFileName(ApplicationConfig.FTP_IMAGE + File.separator + trfObj.getSymbFileNm()); // Ftp 다운로드 명을 설정
                        // 소통등급별 이미지 파일 저장
                        saveByteArrayToFile(trfObj, trfUpdtDt);
                    }
                }

                // 이미지 파일저장
                if (!"SBT3".equals(obj.getSymbType())) {
                    saveByteArrayToFile(obj, updtDt);
                }
            });
        }
        catch (Exception e) {
            log.error("VmsSymbService.loadVmsSymbLib: {}", e.toString());
        }
    }

    public void loadVmsSymbCellInfo() {
        try {
            List<TbVmsSymbIfscDto> infoList  = this.vmsSymbMapper.selectVmsSymbCellInfo();
            log.info("VmsSymbService.loadVmsSymbCellInfo(), {} EA", infoList.size());
            infoList.forEach(dto -> {
                String updtDt = dto.getUpdtDt();
                Integer symbLibNmbr = dto.getSymbLibNmbr();
                TbVmsSymbLib obj = this.symbMap.get(symbLibNmbr + "0");
                if (obj == null) {
                    log.error("VmsSymbService.loadVmsSymbCellInfo: Not Found Cell Info {}.", symbLibNmbr);
                    return;
                }
                TbVmsSymbIfsc cell = dto.toEntity();
                for (Map.Entry<Integer, TbVmsSymbIfsc> cellObj : obj.getCellMap().entrySet()) {
                    if (cellObj.getValue().getVmsIfscId().equals(cell.getVmsIfscId())) {
                        cell.setDup(true);
                        break;
                    }
                }
                obj.getCellMap().put(cell.getCellId(), cell);
            });
        }
        catch (Exception e) {
            log.error("VmsSymbService.loadVmsSymbCellInfo: {}", e.getMessage());
        }
    }

    public boolean saveByteArrayToFile(TbVmsSymbLib obj, String updtDt) {
        boolean result = true;
        File imagFile = new File(obj.getLocalFileName());
        if (!imagFile.exists() || !obj.getUpdtDt().equals(updtDt)) {
            if (imagFile.exists()) {
                boolean deleted = imagFile.delete();
                log.info("VmsSymbService.saveImageFile: Old file deleted {}, {}", obj.getLocalFileName(), deleted);
            }
            result = ItsUtils.saveByteArrayToFile(obj.getLocalFileName(), obj.getImagData());
        }
        obj.setUpdtDt(updtDt);  // 업데이트 시각을 업데이트 한다.
        return result;
    }

    public static int getGradColor(int grad) {
        if (grad == 1) return Color.GREEN.getRGB();
        if (grad == 2) return Color.YELLOW.getRGB();
        if (grad == 3) return Color.RED.getRGB();
        return Color.GRAY.getRGB();
    }

    public static Color getTrafColor(int grad) {
        if (grad == 1) return Color.GREEN;
        if (grad == 2) return Color.YELLOW;
        if (grad == 3) return Color.RED;
        return Color.GRAY;
    }

}
