package com.erp.provisioning;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

/**
 * 진행 중인 프로비저닝 작업의 인메모리 레지스트리.
 * 완료/실패한 최종 상태는 COMPANY_MNG.db_status 에 영속화되므로, 이 레지스트리는
 * "지금 진행 중이거나 방금 끝난" 단기 상태 전용.
 *
 * ★ 2026-04-24 Codex 리뷰 반영:
 *   - 완료/실패 후 TTL 24h 초과하면 자동 제거 (매시간 cleanup).
 *   - 이전 버전: 서버 무중단 운영 시 Map 이 영구 누적.
 */
@Service
@Slf4j
public class ProvisioningRegistry {

    private static final int CLEANUP_TTL_HOURS = 24;

    private final ConcurrentHashMap<String, ProvisioningStatus> jobs = new ConcurrentHashMap<>();

    public void register(ProvisioningStatus status) {
        jobs.put(status.getId(), status);
    }

    public ProvisioningStatus get(String id) {
        return jobs.get(id);
    }

    public void update(String id, Consumer<ProvisioningStatus> updater) {
        jobs.computeIfPresent(id, (k, v) -> {
            updater.accept(v);
            return v;
        });
    }

    public Collection<ProvisioningStatus> list() {
        return Collections.unmodifiableCollection(jobs.values());
    }

    /** 매시간 실행. 완료/실패 상태로 24h 지난 job 을 메모리에서 해제. */
    @Scheduled(fixedDelayString = "${tenant.provisioning.cleanup-ms:3600000}", initialDelay = 600_000)
    public void cleanupExpiredJobs() {
        Instant threshold = Instant.now().minus(CLEANUP_TTL_HOURS, ChronoUnit.HOURS);
        int before = jobs.size();
        jobs.entrySet().removeIf(e -> {
            ProvisioningStatus s = e.getValue();
            String state = s.getStatus();
            boolean done = "completed".equals(state) || "failed".equals(state);
            return done && s.getCompletedAt() != null && s.getCompletedAt().isBefore(threshold);
        });
        int after = jobs.size();
        if (before != after) {
            log.info("[Provisioning] cleanup — removed {} expired jobs, {} remain", before - after, after);
        }
    }
}
