package org.wcs.business.data.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.wcs.business.data.intf.IDataLoader;
import org.wcs.mapper.intf.*;
import org.wcs.model.po.app.*;
import org.wcs.plugin.plc.common.PlcCommonData;
import org.wcs.plugin.plc.model.SiemensDBAddress;
import org.wcs.plugin.webHttpClient.WebHttpClient;
import org.wcs.plugin.webHttpClient.model.HttpAddressKeyItem;
import org.wcs.utils.AppStringUtils;

import java.util.*;

/**
 * 数据加载器
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DataLoader implements IDataLoader {

    private final StringRedisTemplate stringRedisTemplate;
    private final AppStackerInfoService stackerInfoService;
    private final AppStackerStandService stackerStandService;
    private final AppTrayConveyLocationService trayConveyLocationService;
    private final AppConveyLocationService conveyLocationService;
    private final AppBaseDbService baseDbService;
    private final AppStockScanService stockScanService;
    private final AppBaseApiInfoService baseApiInfoService;

    /**
     * 加载DB地址 ---- 总方法
     */
    @Override
    public void loadDBAddress() {
        clearDBAddressRedis(); // 清理DB地址缓存
        loadStackerDBAddress(); // 加载堆垛机DB地址
        loadStackerStandDBAddress(); // 加载堆垛机站台DB地址
        loadTrayConveyDBAddress(); // 加载托盘输送DB地址
        loadConveyDBAddress(); // 加载箱式线输送DB地址
        loadScannerDBAddress(); // 加载扫描器DB地址
        loadDbTableAddress(); // 加载数据库表地址
    }

    /**
     * 清除DB地址缓存
     */
    @Override
    public void clearDBAddressRedis() {
        Set<String> keys = stringRedisTemplate.keys(PlcCommonData.PLC_DB_ADDRESS_REDIS_KEY + ":*");
        long delete = stringRedisTemplate.delete(keys);
        log.info("清除DB地址缓存结果：{}", delete);
    }

    /**
     * 加载堆垛机数据DB地址
     */
    @Override
    public void loadStackerDBAddress() {
        List<AppStackerInfo> stackerInfos = stackerInfoService.queryAll(); // 堆垛机信息
        if(stackerInfos == null) {
            log.error("加载堆垛机DB信息时堆垛机信息数据库访问异常");
            return; // 堆垛机信息数据库访问异常
        }
        Map<String, SiemensDBAddress> siemensDBAddressMap = new HashMap<>();
        // 加载堆垛机DB数据
        for (AppStackerInfo stackerInfo : stackerInfos) {
            // 读取堆垛机状态
            SiemensDBAddress readStatusDbAddress = new SiemensDBAddress();
            readStatusDbAddress.setPlcId(stackerInfo.getPlcId());
            readStatusDbAddress.setDbName("*堆垛机状态"+stackerInfo.getStackerId());
            readStatusDbAddress.setDbAddress(stackerInfo.getReadStatusAddress());
            siemensDBAddressMap.put(readStatusDbAddress.getDbName(), readStatusDbAddress);
            // 写入堆垛机任务
            SiemensDBAddress writeTaskDbAddress = new SiemensDBAddress();
            writeTaskDbAddress.setPlcId(stackerInfo.getPlcId());
            writeTaskDbAddress.setDbName("*堆垛机写任务"+stackerInfo.getStackerId());
            writeTaskDbAddress.setDbAddress(stackerInfo.getWriteTaskAddress());
            siemensDBAddressMap.put(writeTaskDbAddress.getDbName(), writeTaskDbAddress);
            // 堆垛机任务确认
            if(AppStringUtils.isNotEmpty(stackerInfo.getTaskConfirmAddress())) {
                SiemensDBAddress taskConfirmDbAddress = new SiemensDBAddress();
                taskConfirmDbAddress.setPlcId(stackerInfo.getPlcId());
                taskConfirmDbAddress.setDbName("*堆垛机写任务确认"+stackerInfo.getStackerId());
                taskConfirmDbAddress.setDbAddress(stackerInfo.getTaskConfirmAddress());
                siemensDBAddressMap.put(taskConfirmDbAddress.getDbName(), taskConfirmDbAddress);
            }
            // 堆垛机过账区
            SiemensDBAddress taskStatusDbAddress = new SiemensDBAddress();
            taskStatusDbAddress.setPlcId(stackerInfo.getPlcId());
            taskStatusDbAddress.setDbName("*堆垛机过账区"+stackerInfo.getStackerId());
            taskStatusDbAddress.setDbAddress(stackerInfo.getTaskStatusAddress());
            siemensDBAddressMap.put(taskStatusDbAddress.getDbName(), taskStatusDbAddress);
        }
        log.info("堆垛机DB数据加载完成，数据行数：{}", siemensDBAddressMap.size());
        siemensDBAddressMap.forEach((dbName, dbAddress) -> {
            stringRedisTemplate.opsForValue().set(PlcCommonData.PLC_DB_ADDRESS_REDIS_KEY + ":" + dbName, AppStringUtils.objectToString(dbAddress));
        });
    }

    /**
     * 加载堆垛机站台数据DB地址
     */
    @Override
    public void loadStackerStandDBAddress() {
        List<AppStackerStand> stackerStands = stackerStandService.queryAll(); // 堆垛机站台信息
        if(stackerStands == null) {
            log.error("加载堆垛机DB信息时堆垛机站台信息数据库访问异常");
            return; // 堆垛机信息数据库访问异常
        }
        Map<String, SiemensDBAddress> siemensDBAddressMap = new HashMap<>();
        // 加载堆垛机站台DB数据
        for (AppStackerStand stackerStand : stackerStands) {
            // 读取站台状态
            if(AppStringUtils.isNotEmpty(stackerStand.getReadStatusAddress())) {
                SiemensDBAddress readStatusDbAddress = new SiemensDBAddress();
                readStatusDbAddress.setPlcId(stackerStand.getPlcId());
                readStatusDbAddress.setDbName("*输送机状态"+stackerStand.getStandId());
                readStatusDbAddress.setDbAddress(stackerStand.getReadStatusAddress());
                siemensDBAddressMap.put(readStatusDbAddress.getDbName(), readStatusDbAddress);
            }
            // 写入站台任务
            if(AppStringUtils.isNotEmpty(stackerStand.getWriteTaskAddress())) {
                SiemensDBAddress writeTaskDbAddress = new SiemensDBAddress();
                writeTaskDbAddress.setPlcId(stackerStand.getPlcId());
                writeTaskDbAddress.setDbName("*输送机写任务"+stackerStand.getStandId());
                writeTaskDbAddress.setDbAddress(stackerStand.getWriteTaskAddress());
                siemensDBAddressMap.put(writeTaskDbAddress.getDbName(), writeTaskDbAddress);
            }
        }
        log.info("堆垛机站台DB数据加载完成，数据行数：{}", siemensDBAddressMap.size());
        siemensDBAddressMap.forEach((dbName, dbAddress) -> {
            stringRedisTemplate.opsForValue().set(PlcCommonData.PLC_DB_ADDRESS_REDIS_KEY + ":" + dbName, AppStringUtils.objectToString(dbAddress));
        });
    }

    /**
     * 加载托盘传送数据DB地址
     */
    @Override
    public void loadTrayConveyDBAddress() {
        List<AppTrayConveyLocation> trayConveyLocations = trayConveyLocationService.queryAll();
        if(trayConveyLocations == null) {
            log.error("加载托盘传送DB信息时托盘传送信息数据库访问异常");
            return;
        }
        Map<String, SiemensDBAddress> siemensDBAddressMap = new HashMap<>();
        for (AppTrayConveyLocation trayConveyLocation : trayConveyLocations) {
            if(AppStringUtils.isNotEmpty(trayConveyLocation.getReadStatusAddress())) {
                SiemensDBAddress readStatusDbAddress = new SiemensDBAddress();
                readStatusDbAddress.setPlcId(trayConveyLocation.getPlcId());
                readStatusDbAddress.setDbName("*输送机状态"+trayConveyLocation.getLocationId());
                readStatusDbAddress.setDbAddress(trayConveyLocation.getReadStatusAddress());
                siemensDBAddressMap.put(readStatusDbAddress.getDbName(), readStatusDbAddress);
            }
            if(AppStringUtils.isNotEmpty(trayConveyLocation.getWriteTaskAddress())) {
                SiemensDBAddress writeTaskDbAddress = new SiemensDBAddress();
                writeTaskDbAddress.setPlcId(trayConveyLocation.getPlcId());
                writeTaskDbAddress.setDbName("*输送机写任务"+trayConveyLocation.getLocationId());
                writeTaskDbAddress.setDbAddress(trayConveyLocation.getWriteTaskAddress());
                siemensDBAddressMap.put(writeTaskDbAddress.getDbName(), writeTaskDbAddress);
            }
        }
        log.info("初始化托盘输送DB数据完成，数据行数：{}", siemensDBAddressMap.size());
        siemensDBAddressMap.forEach((dbName, dbAddress) -> {
            stringRedisTemplate.opsForValue().set(PlcCommonData.PLC_DB_ADDRESS_REDIS_KEY + ":" + dbName, AppStringUtils.objectToString(dbAddress));
        });
    }

    /**
     * 加载箱式线输送的DB地址
     */
    @Override
    public void loadConveyDBAddress() {
        List<AppConveyLocation> conveyLocations = conveyLocationService.queryAll();
        if(conveyLocations == null) {
            log.error("加载箱式线输送DB信息时托盘传送信息数据库访问异常");
            return;
        }
        Map<String, SiemensDBAddress> siemensDBAddressMap = new HashMap<>();
        for(AppConveyLocation conveyLocation : conveyLocations) {
            /* 读取状态地址 */
            if(AppStringUtils.isNotEmpty(conveyLocation.getReadStatusAddress())) {
                SiemensDBAddress readStatusDbAddress = new SiemensDBAddress();
                readStatusDbAddress.setPlcId(conveyLocation.getPlcId());
                readStatusDbAddress.setDbName("*输送机状态"+conveyLocation.getLocationId());
                readStatusDbAddress.setDbAddress(conveyLocation.getReadStatusAddress());
                siemensDBAddressMap.put(readStatusDbAddress.getDbName(), readStatusDbAddress);
            }
            /* 写入任务地址 */
            if(AppStringUtils.isNotEmpty(conveyLocation.getWriteTaskAddress())) {
                SiemensDBAddress writeTaskDbAddress = new SiemensDBAddress();
                writeTaskDbAddress.setPlcId(conveyLocation.getPlcId());
                writeTaskDbAddress.setDbName("*输送机写任务"+conveyLocation.getLocationId());
                writeTaskDbAddress.setDbAddress(conveyLocation.getWriteTaskAddress());
                siemensDBAddressMap.put(writeTaskDbAddress.getDbName(), writeTaskDbAddress);
            }
        }

        log.info("初始化箱式线输送DB地址完成，数据行数：{}", siemensDBAddressMap.size());
        siemensDBAddressMap.forEach((dbName, dbAddress) -> {
            stringRedisTemplate.opsForValue().set(PlcCommonData.PLC_DB_ADDRESS_REDIS_KEY + ":" + dbName, AppStringUtils.objectToString(dbAddress));
        });
    }

    /**
     * 加载DB数据表的地址
     */
    @Override
    public void loadDbTableAddress() {
        List<AppBaseDb> appBaseDbs = baseDbService.queryAll();
        if(appBaseDbs == null) {
            log.error("加载DB数据库表信息时数据库表信息数据库访问异常");
            return;
        }
        Map<String, SiemensDBAddress> siemensDBAddressMap = new HashMap<>();
        for(AppBaseDb appBaseDb : appBaseDbs) {
            SiemensDBAddress baseDbAddress = new SiemensDBAddress();
            baseDbAddress.setPlcId(appBaseDb.getPlcId());
            baseDbAddress.setDbName(appBaseDb.getDbName());
            baseDbAddress.setDbAddress(appBaseDb.getDbAddress());
            siemensDBAddressMap.put(baseDbAddress.getDbName(), baseDbAddress);
        }
        log.info("初始化DB地址表完成，数据行数：{}", siemensDBAddressMap.size());
        siemensDBAddressMap.forEach((dbName, dbAddress) -> {
            stringRedisTemplate.opsForValue().set(PlcCommonData.PLC_DB_ADDRESS_REDIS_KEY + ":" + dbName, AppStringUtils.objectToString(dbAddress));
        });
    }

    /**
     * 加载扫描器DB地址
     */
    @Override
    public void loadScannerDBAddress() {
        List<AppStockScan> stockScans = stockScanService.queryAll();
        if(stockScans == null) {
            log.error("加载扫描器DB信息时扫描器信息数据库访问异常");
            return;
        }
        Map<String, SiemensDBAddress> siemensDBAddressMap = new HashMap<>();
        for (AppStockScan stockScan : stockScans) {
            /* 读取状态地址 */
            if(AppStringUtils.isNotEmpty(stockScan.getReadStatusAddress())) {
                SiemensDBAddress readStatusDbAddress = new SiemensDBAddress();
                readStatusDbAddress.setPlcId(stockScan.getPlcId());
                readStatusDbAddress.setDbName("*扫码器数据"+stockScan.getScanId());
                readStatusDbAddress.setDbAddress(stockScan.getReadStatusAddress());
                siemensDBAddressMap.put(readStatusDbAddress.getDbName(), readStatusDbAddress);
            }
            /* 写入任务地址 */
            if(AppStringUtils.isNotEmpty(stockScan.getWriteTaskAddress())) {
                SiemensDBAddress writeTaskDbAddress = new SiemensDBAddress();
                writeTaskDbAddress.setPlcId(stockScan.getPlcId());
                writeTaskDbAddress.setDbName("*扫码器写任务"+stockScan.getScanId());
                writeTaskDbAddress.setDbAddress(stockScan.getWriteTaskAddress());
                siemensDBAddressMap.put(writeTaskDbAddress.getDbName(), writeTaskDbAddress);
            }
        }
        log.info("初始化扫描器DB地址完成，数据行数：{}", siemensDBAddressMap.size());
        siemensDBAddressMap.forEach((dbName, dbAddress) -> {
            stringRedisTemplate.opsForValue().set(PlcCommonData.PLC_DB_ADDRESS_REDIS_KEY + ":" + dbName, AppStringUtils.objectToString(dbAddress));
        });
    }

    /**
     * 加载API基础资料
     */
    @Override
    public void loadApiKey() {
        List<AppBaseApiInfo> baseApiInfos = baseApiInfoService.queryAll();
        if(baseApiInfos == null) {
            log.error("加载API基础资料时数据库访问异常");
            return;
        }
        List<HttpAddressKeyItem> addressKeyList = new ArrayList<>();
        for (AppBaseApiInfo baseApiInfo : baseApiInfos) {
            HttpAddressKeyItem addressKeyItem = new HttpAddressKeyItem();
            addressKeyItem.setKey(baseApiInfo.getApiKey());
            addressKeyItem.setAddress(baseApiInfo.getAddress());
            addressKeyItem.setFatherKey(baseApiInfo.getRootKey());
            addressKeyList.add(addressKeyItem);
        }
        log.info("API基础资料加载完成，数据行数：{}", addressKeyList.size());
        WebHttpClient.setAddressKey(addressKeyList);
    }
}
