package com.tsi.comm.server.repository;

import com.tsi.comm.server.vo.TsiNodeVo;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

@Slf4j
@Getter
@RequiredArgsConstructor
@Component
public class TsiNodeManager {

    private final ConcurrentHashMap<Long, TsiNodeVo> tsiNodeVoMap = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, TsiNodeVo> ipAddrMap = new ConcurrentHashMap<>();

    /**
     * nodeId에 해당하는 TsiNodeVo가 없으면, 주어진 함수를 통해 생성하고 맵에 추가한 후 반환합니다.
     * 이 모든 과정은 ConcurrentHashMap의 computeIfAbsent를 통해 원자적으로 처리됩니다.
     * @param nodeId 노드 ID
     * @param mappingFunction TsiNodeVo가 없을 때 새로 생성하기 위한 람다 함수 (Java 8의 Function 인터페이스)
     * @return 맵에 존재하거나 새로 생성된 TsiNodeVo 객체
     */
    public TsiNodeVo getOrCompute(long nodeId, Function<Long, TsiNodeVo> mappingFunction) {
        return this.tsiNodeVoMap.computeIfAbsent(nodeId, mappingFunction);
    }

    public TsiNodeVo get(long nodeId) {
        return this.tsiNodeVoMap.get(nodeId);
    }
    public void put(long nodeId, TsiNodeVo vo) {
        this.tsiNodeVoMap.put(nodeId, vo);
    }

    public int size() {
        return this.tsiNodeVoMap.size();
    }

    public TsiNodeVo getIpAddr(String ipAddr) {
        if (ipAddr == null || ipAddr.isEmpty()) {
            return null;
        }
        return this.ipAddrMap.get(ipAddr);
    }
    public void putIpAddr(String ipAddr, TsiNodeVo vo) {
        if (ipAddr == null || ipAddr.isEmpty()) {
            return;
        }
        this.ipAddrMap.put(ipAddr, vo);
    }
    public void removeIpAddr(String ipAddr) {
        if (ipAddr == null || ipAddr.isEmpty()) {
            return;
        }
        this.ipAddrMap.remove(ipAddr);
    }

    public int sizeIpAddr() {
        return this.ipAddrMap.size();
    }

    public boolean containsKey(long key) {
        return this.tsiNodeVoMap.containsKey(key);
    }

    public void beforeLoading() {
        for (Map.Entry<Long, TsiNodeVo> obj : this.tsiNodeVoMap.entrySet()) {
            obj.getValue().setCheckInstalled(false);
        }
    }

    public void afterLoading() {
        for (Map.Entry<Long, TsiNodeVo> obj : this.tsiNodeVoMap.entrySet()) {
            if (obj.getValue().isRegistered()) {
                obj.getValue().setInstalled(obj.getValue().isCheckInstalled());
            }
        }
    }

    public void initDump() {
        for (Map.Entry<Long, TsiNodeVo> obj : this.tsiNodeVoMap.entrySet()) {
            TsiNodeVo node = obj.getValue();
            node.setDump(false);
        }
    }

}
