package com.tsi.comm.server.service;

import com.tsi.comm.server.config.TsiCvimServerConfig;
import com.tsi.comm.server.vo.TsiNodeVo;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.concurrent.atomic.AtomicIntegerArray;

@Slf4j
@Getter
@Setter
@Service
public class TsiQueueDistributorService {

    private final TsiCvimServerConfig serverConfig;

    private final AtomicIntegerArray packetLoads;
    private final AtomicIntegerArray dbmsLoads;
    private final AtomicIntegerArray logLoads;

    public TsiQueueDistributorService(TsiCvimServerConfig serverConfig) {
        this.serverConfig = serverConfig;
        this.packetLoads = new AtomicIntegerArray(this.serverConfig.getPacketWorkers());
        this.dbmsLoads = new AtomicIntegerArray(this.serverConfig.getDbmsWorkers());
        this.logLoads = new AtomicIntegerArray(this.serverConfig.getLoggingWorkers());
    }

    private int getLeastLoadedQueue(AtomicIntegerArray loads) {
        int length = loads.length();
        if (length == 0) {
            return 0;
        }

        int minIndex = 0;
        int minLoad = loads.get(0);

        for (int ii = 1; ii < length; ii++) {
            int current = loads.get(ii);
            if (current < minLoad) {
                minLoad = current;
                minIndex = ii;
            }
        }
        loads.incrementAndGet(minIndex); // 새로운 장비 배정
        return minIndex;
    }

    public synchronized void setLoadedQueue(TsiNodeVo node) {
        int packetIdx = getLeastLoadedQueue(this.packetLoads);
        int dbmsIdx = getLeastLoadedQueue(this.dbmsLoads);
        int loggingIdx = getLeastLoadedQueue(this.logLoads);
        node.setPktQIdx(packetIdx);
        node.setDbmsQIdx(dbmsIdx);
        node.setLogQIdx(loggingIdx);
    }

    public synchronized void releaseQueue(int pktQIdx, int dbmsQIdx, int logQIdx) {
        if (pktQIdx >= 0 && pktQIdx < this.packetLoads.length()) {
            this.packetLoads.decrementAndGet(pktQIdx);
        }
        if (dbmsQIdx >= 0 && dbmsQIdx < this.dbmsLoads.length()) {
            this.dbmsLoads.decrementAndGet(dbmsQIdx);
        }
        if (logQIdx >= 0 && logQIdx < this.logLoads.length()) {
            this.logLoads.decrementAndGet(logQIdx);
        }
    }

    public void logQueueLoads() {
        StringBuilder packetSb = new StringBuilder();
        for (int i = 0; i < this.packetLoads.length(); i++) {
            packetSb.append("[").append(i).append(":").append(this.packetLoads.get(i)).append("] ");
        }

        StringBuilder dbmsSb = new StringBuilder();
        for (int i = 0; i < this.dbmsLoads.length(); i++) {
            dbmsSb.append("[").append(i).append(":").append(this.dbmsLoads.get(i)).append("] ");
        }

        StringBuilder logSb = new StringBuilder();
        for (int i = 0; i < this.logLoads.length(); i++) {
            logSb.append("[").append(i).append(":").append(this.logLoads.get(i)).append("] ");
        }
        log.info("PacketLoads: {} EA. {}", this.packetLoads.length(), packetSb);
        log.info("DbmsLoads: {} EA. {}", this.dbmsLoads.length(), dbmsSb);
        log.info("LogLoads: {} EA. {}", this.logLoads.length(), logSb);
    }
}
