package com.pwt;

import com.pwt.common.enums.ChargerFault;
import com.pwt.common.utils.spring.SpringUtils;
import com.pwt.netty.ChargerServer;
import com.pwt.netty.Vehicle2Server;
import com.pwt.netty.client.CodeScannerClient;
import com.pwt.netty.client.PlcClient;
import com.pwt.netty.client.RFIDClient;
import com.pwt.netty.common.StringUtils;
import com.pwt.netty.common.constants.Constants;
import com.pwt.netty.message2.*;
import com.pwt.netty.server.NettyServer;
import com.pwt.system.domain.PwtConfig;
import com.pwt.system.service.IPwtConfigService;
import com.pwt.web.domain.ExchangeStatistics;
import com.pwt.web.domain.PwtHolderBatteryStateCache;
import com.pwt.web.domain.StatisticsRecord;
import com.pwt.web.service.IPwtChangeBatteryRecordService;
import com.pwt.web.service.IPwtChargeRecordService;
import com.pwt.web.service.IPwtHolderBatteryStateCacheService;
import com.pwt.web.service.IPwtVehicleService;
import io.netty.channel.ChannelFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.pwt.Globals.*;
import static com.pwt.netty.handler.ChargerServerHandler.GUN_AND_HOLDER_MAP;
import static com.pwt.netty.handler.ChargerServerHandler.HOLDER_AND_GUN_MAP;

/**
 * 启动程序
 */
@EnableScheduling
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class PwtApplication implements CommandLineRunner {

    @Autowired
    private CodeScannerClient codeScannerClient;

    @Autowired
    private RFIDClient rfidClient;

    @Autowired
    private Vehicle2Server vehicleServer;

    @Autowired
    private ChargerServer chargerServer;

    @Autowired
    private PlcClient plcClient;

    @Autowired
    private IPwtChangeBatteryRecordService changeBatteryRecordService;

    @Autowired
    private IPwtChargeRecordService chargeRecordService;

    @Autowired
    private IPwtVehicleService vehicleService;

    @Autowired
    private IPwtConfigService configService;

    @Autowired
    private IPwtHolderBatteryStateCacheService holderBatteryStateCacheService;

    public static void main(String[] args) {
        // System.setProperty("spring.devtools.restart.enabled", "false");
        SpringApplication.run(PwtApplication.class, args);
        System.out.println("站控系统启动成功...");
    }

    @Override
    public void run(String... args) throws Exception {
        // 加载枪号,仓位,充电机信息
        PwtConfig pwtConfig = configService.selectPwtConfigById(1L);
        initChargerAndGun(pwtConfig);
        initGlobalsInfo();

        Map<Integer, PwtHolderBatteryStateCache> batteryStateCacheMap = holderBatteryStateCacheService.getBatteryStateCacheMap();

        if (batteryStateCacheMap != null) {
            Globals.holderBatteryStateCacheMap = new ConcurrentHashMap<>(batteryStateCacheMap);
        }

        ExchangeStatistics exchangeStatistics = changeBatteryRecordService.getExchangeStatistics();
        if (pwtConfig != null && pwtConfig.getChargeSoc() != null) {
            StationService.GET_SOC = pwtConfig.getChargeSoc().intValue();
        }
        // 使用电量
        List<StatisticsRecord> statisticsRecord = chargeRecordService.getStatisticsRecord(new StatisticsRecord());
        BigDecimal totalUsedPower = statisticsRecord.stream().map(StatisticsRecord::getChargeQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);

        Globals.OP_REGISTER_CAR_COUNT.set(vehicleService.getCount());
        Globals.OP_EXCHANGE_COUNT.set(exchangeStatistics.getCount());
//        Globals.OP_EXCHANGE_POWER.set(exchangeStatistics.getExchangePower());
        // 换电量改成用电量
        Globals.OP_EXCHANGE_POWER.set(totalUsedPower.doubleValue());

        OperationData operationData = new OperationData();
        Duration d = Duration.between(Globals.startDateTime, LocalDateTime.now());
        operationData.setDays(d.toDays());
        operationData.setTotalExchangePower(Globals.OP_EXCHANGE_POWER.get());
        operationData.setTotalExchangeCount(Globals.OP_EXCHANGE_COUNT.get());
        operationData.setTotalRegisterCount(Globals.OP_REGISTER_CAR_COUNT.get());
        Globals.uiData.setOperationData(operationData);

        // todo 链接断线监控
        Globals.plcClient = plcClient;
        plcClient.start();
        codeScannerClient.start();
        rfidClient.start();
        vehicleServer.start();
        chargerServer.start();
        NettyServer nettyServer = SpringUtils.getBean(NettyServer.class);
        ChannelFuture future = nettyServer.start();
    }

    /**
     * 初始化界面信息
     */
    private void initGlobalsInfo() {
        // 仓位
        ArrayList<BatteryHolder> holders = new ArrayList<>(MAX_HOLDER_COUNT);
        for (int i = 1; i <= MAX_HOLDER_COUNT; i++) {
            BatteryHolder holder = new BatteryHolder();
            holder.setIndex(i);
            holder.setId(String.valueOf(i));
            holder.setName("#"+i);
            if(i> ACTUAL_HOLDER_COUNT) {
                holder.setEnable(false);
            }
            holders.add(holder);
        }
        uiData.setBatteryHolders(holders);

        // 充电机
        int chargerCount = CHARGER_CONFIGS.size();
        ArrayList<Charger> chargers = new ArrayList<>(chargerCount);
        ArrayList<ChargerGun> guns = new ArrayList<>();
        for (int i = 1; i <= chargerCount ; i++) {
            ChargerConfig chargerConfig = CHARGER_CONFIGS.get(i - 1);
            Charger c = new Charger();
            c.setCommunicationState(Constants.NET_CONNECTION_STATE_OFFLINE);
            c.setId(chargerConfig.getId());

            c.setName("#"+i);
            c.setIndex(i);
            List<ChargerModule> modules = new ArrayList<>(MAX_CHARGER_MODULE_COUNT);
            for (int j = 1; j <= MAX_CHARGER_MODULE_COUNT ; j++) {
                ChargerModule m = new ChargerModule();
                m.setIndex(j);
                modules.add(m);
            }
            c.setChargeModule(modules);
            c.setEnableEmergency(chargerConfig.isEnableEmergency());
            chargers.add(c);

            // 计算枪的数量（主枪和应急充电枪），默认一个充电机只有一个主枪
            int gunCount = 1;

            // 仅显示主枪
            if(i == 1) {
                // 仓位配置2，1拖2，有2把主枪
                if(HOLDER_CONFIG_TYPE == 2) {
                    gunCount = 2;
                }
            }
            // 其他的枪可以设置为应急充电枪，此时除了1把主枪还有两把枪可以做为应急充电枪
            else if(chargerConfig.isEnableEmergency()) {
                Globals.emergencyChargerId = chargerConfig.getId();
                gunCount = 3;
            }

            for (int j = 1; j <= gunCount ; j++) {
                // 计算枪号
                int gunNo;
                // 1拖1时，主枪为1号
                if(gunCount == 1) {
                    gunNo = 1;
                }
                // 1拖2时，主枪为1号,3号
                else if(gunCount == 2) {
                    if(j == 1) {
                        gunNo = 1;
                    } else {
                        gunNo = 3;
                    }
                } else {
                    // 带有应急充电枪的充电机
                    // #1为仓位使用的充电机
                    if(j == 1) {
                        gunNo = 1;
                    } else {
                        // #3,#4为外作为应急充电枪
                        gunNo = j + 1;
                    }
                }

                int holderId = 0;
                if(HOLDER_CONFIG_TYPE == 1) {
                    // 配置1 仓位和充电机一样多
                    // 只有主枪在仓位上
                    if(gunNo == 1) {
                        holderId = i;
                    }
                } else {
                    // 配置2
                    // 第一个充电机
                    if(i == 1) {
                        // 1,2 在3号仓
                        if(gunNo == 1) {
                            holderId = 3;
                        } else {
                            // 3,4 在1号仓
                            holderId = 1;
                        }
                    } else if(i == 2) {
                        // 第2个充电机
                        if(gunNo == 1) {
                            holderId = 2;
                        }
                    } else {
                        // 其他充电机所在仓位往后顺延1个
                        if(gunNo == 1) {
                            holderId = i + 1;
                        }
                    }
                }
                String holderIdStr;
                if(holderId == 0) {
                    holderIdStr = null;
                } else {
                    holderIdStr = String.valueOf(holderId);
                }
                ChargerGun gun = new ChargerGun();
                gun.setHolderId(holderIdStr);
                gun.setIndex(j);
                gun.setName("#"+gunNo);
                gun.setChargerId(c.getId());
                gun.setId(c.getId()+gunNo);
                guns.add(gun);
                GUN_INDEX_MAP.put(gun.getId(), guns.size());
            }
        }
        uiData.setChargers(chargers);
        uiData.setChargerGuns(guns);

        // 运营数据
        uiData.setOperationData(new OperationData());
        AvailableBatteryStats availableBatteryStats = new AvailableBatteryStats(ACTUAL_HOLDER_COUNT);
        uiData.setAvailableBatteryStats(availableBatteryStats);

        // 初始化数量
        for (int i = 1 ; i <=5; i++) {
            AlarmStatistics alarmStatistics = new AlarmStatistics();
            alarmStatistics.setSourceDeviceType(i);
            alarmStatistics.setCount(0);
            uiData.getAlarmStats().add(alarmStatistics);
        }

        for (ChargerFault value : ChargerFault.values()) {
            Globals.uiData.getGunAlarms().add(new GunAlarmTemplate(value.getErrCode()+"", value.getErrMsg()));
        }
    }

    /**
     * 初始化仓位和枪号配置
     * @param pwtConfig
     */
    public void initChargerAndGun(PwtConfig pwtConfig) {
        String defaultKey = "0";
        if (StringUtils.isNotEmpty(pwtConfig.getCharger1No()) && !defaultKey.equals(pwtConfig.getCharger1No())) {
            GUN_AND_HOLDER_MAP.put(pwtConfig.getCharger1No(), 1);
            HOLDER_AND_GUN_MAP.put(1, pwtConfig.getCharger1No());

            // 1号仓位充电机
            Globals.ChargerConfig chargeConfig1 = new Globals.ChargerConfig();
            chargeConfig1.setIp(pwtConfig.getCharger1Ip());
            chargeConfig1.setId(pwtConfig.getCharger1No().substring(0, pwtConfig.getCharger1No().length() - 1));
            chargeConfig1.setEnableEmergency(pwtConfig.getCharger1Emg());
            CHARGE_INDEX_MAP.put(pwtConfig.getCharger1No().substring(0, pwtConfig.getCharger1No().length() - 1), 1);
            CHARGER_CONFIGS.add(chargeConfig1);
        }

        if (StringUtils.isNotEmpty(pwtConfig.getCharger2No()) && !defaultKey.equals(pwtConfig.getCharger2No())) {
            GUN_AND_HOLDER_MAP.put(pwtConfig.getCharger2No(), 2);
            HOLDER_AND_GUN_MAP.put(2, pwtConfig.getCharger2No());

            // 2号仓位充电机
            Globals.ChargerConfig chargeConfig2 = new Globals.ChargerConfig();
            chargeConfig2.setIp(pwtConfig.getCharger2Ip());
            chargeConfig2.setId(pwtConfig.getCharger2No().substring(0, pwtConfig.getCharger2No().length() - 1));
            chargeConfig2.setEnableEmergency(pwtConfig.getCharger2Emg());
            CHARGE_INDEX_MAP.put(pwtConfig.getCharger2No().substring(0, pwtConfig.getCharger2No().length() - 1), 2);
            CHARGER_CONFIGS.add(chargeConfig2);
        }

        if (StringUtils.isNotEmpty(pwtConfig.getCharger3No()) && !defaultKey.equals(pwtConfig.getCharger3No())) {
            GUN_AND_HOLDER_MAP.put(pwtConfig.getCharger3No(), 3);
            HOLDER_AND_GUN_MAP.put(3, pwtConfig.getCharger3No());

            // 不带一拖二的充电机
            if (Globals.HOLDER_CONFIG_TYPE == 1) {
                // 3号仓位充电机
                Globals.ChargerConfig chargeConfig3 = new Globals.ChargerConfig();
                chargeConfig3.setIp(pwtConfig.getCharger3Ip());
                chargeConfig3.setId(pwtConfig.getCharger3No().substring(0, pwtConfig.getCharger3No().length() - 1));
                chargeConfig3.setEnableEmergency(pwtConfig.getCharger3Emg());
                CHARGE_INDEX_MAP.put(pwtConfig.getCharger3No().substring(0, pwtConfig.getCharger3No().length() - 1), CHARGER_CONFIGS.size() + 1);
                CHARGER_CONFIGS.add(chargeConfig3);
            }
        }

        if (StringUtils.isNotEmpty(pwtConfig.getCharger4No()) && !defaultKey.equals(pwtConfig.getCharger4No())) {
            GUN_AND_HOLDER_MAP.put(pwtConfig.getCharger4No(), 4);
            HOLDER_AND_GUN_MAP.put(4, pwtConfig.getCharger4No());

            // 4号仓位充电机
            Globals.ChargerConfig chargeConfig4 = new Globals.ChargerConfig();
            chargeConfig4.setIp(pwtConfig.getCharger4Ip());
            chargeConfig4.setId(pwtConfig.getCharger4No().substring(0, pwtConfig.getCharger4No().length() - 1));
            chargeConfig4.setEnableEmergency(pwtConfig.getCharger4Emg());
            CHARGE_INDEX_MAP.put(pwtConfig.getCharger4No().substring(0, pwtConfig.getCharger4No().length() - 1), CHARGER_CONFIGS.size() + 1);
            CHARGER_CONFIGS.add(chargeConfig4);
        }

        if (StringUtils.isNotEmpty(pwtConfig.getCharger5No()) && !defaultKey.equals(pwtConfig.getCharger5No())) {
            GUN_AND_HOLDER_MAP.put(pwtConfig.getCharger5No(), 5);
            HOLDER_AND_GUN_MAP.put(5, pwtConfig.getCharger5No());

            // 5号仓位充电机
            Globals.ChargerConfig chargeConfig5 = new Globals.ChargerConfig();
            chargeConfig5.setIp(pwtConfig.getCharger5Ip());
            chargeConfig5.setId(pwtConfig.getCharger5No().substring(0, pwtConfig.getCharger5No().length() - 1));
            chargeConfig5.setEnableEmergency(pwtConfig.getCharger5Emg());
            CHARGE_INDEX_MAP.put(pwtConfig.getCharger5No().substring(0, pwtConfig.getCharger5No().length() - 1), CHARGER_CONFIGS.size() + 1);
            CHARGER_CONFIGS.add(chargeConfig5);
        }

        if (StringUtils.isNotEmpty(pwtConfig.getCharger6No()) && !defaultKey.equals(pwtConfig.getCharger6No())) {
            GUN_AND_HOLDER_MAP.put(pwtConfig.getCharger6No(), 6);
            HOLDER_AND_GUN_MAP.put(6, pwtConfig.getCharger6No());

            // 6号仓位充电机
            Globals.ChargerConfig chargeConfig6 = new Globals.ChargerConfig();
            chargeConfig6.setIp(pwtConfig.getCharger6Ip());
            chargeConfig6.setId(pwtConfig.getCharger6No().substring(0, pwtConfig.getCharger6No().length() - 1));
            chargeConfig6.setEnableEmergency(pwtConfig.getCharger6Emg());
            CHARGE_INDEX_MAP.put(pwtConfig.getCharger6No().substring(0, pwtConfig.getCharger6No().length() - 1), CHARGER_CONFIGS.size() + 1);
            CHARGER_CONFIGS.add(chargeConfig6);
        }

        if (StringUtils.isNotEmpty(pwtConfig.getCharger7No()) && !defaultKey.equals(pwtConfig.getCharger7No())) {
            GUN_AND_HOLDER_MAP.put(pwtConfig.getCharger7No(), 7);
            HOLDER_AND_GUN_MAP.put(7, pwtConfig.getCharger7No());

            // 7号仓位充电机
            Globals.ChargerConfig chargeConfig7 = new Globals.ChargerConfig();
            chargeConfig7.setIp(pwtConfig.getCharger7Ip());
            chargeConfig7.setId(pwtConfig.getCharger7No().substring(0, pwtConfig.getCharger7No().length() - 1));
            chargeConfig7.setEnableEmergency(pwtConfig.getCharger7Emg());
            CHARGE_INDEX_MAP.put(pwtConfig.getCharger7No().substring(0, pwtConfig.getCharger7No().length() - 1), CHARGER_CONFIGS.size() + 1);
            CHARGER_CONFIGS.add(chargeConfig7);
        }

        if (StringUtils.isNotEmpty(pwtConfig.getCharger8No()) && !defaultKey.equals(pwtConfig.getCharger8No())) {
            GUN_AND_HOLDER_MAP.put(pwtConfig.getCharger8No(), 8);
            HOLDER_AND_GUN_MAP.put(8, pwtConfig.getCharger8No());

            // 8号仓位充电机
            Globals.ChargerConfig chargeConfig8 = new Globals.ChargerConfig();
            chargeConfig8.setIp(pwtConfig.getCharger8Ip());
            chargeConfig8.setId(pwtConfig.getCharger8No().substring(0, pwtConfig.getCharger8No().length() - 1));
            chargeConfig8.setEnableEmergency(pwtConfig.getCharger8Emg());
            CHARGE_INDEX_MAP.put(pwtConfig.getCharger8No().substring(0, pwtConfig.getCharger8No().length() - 1), CHARGER_CONFIGS.size() + 1);
            CHARGER_CONFIGS.add(chargeConfig8);
        }
    }
}
