package io.cameleer.server.app.controller;

import io.cameleer.server.app.license.LicenseMessageRenderer;
import io.cameleer.server.app.license.LicenseRepository;
import io.cameleer.server.app.license.LicenseService;
import io.cameleer.server.app.license.LicenseUsageReader;
import io.cameleer.server.core.agent.AgentRegistryService;
import io.cameleer.server.core.license.LicenseGate;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Read-only operator surface returning current license state, key timestamps, the
 * human-readable message produced by {@link LicenseMessageRenderer}, and a per-limit
 * usage/cap/source table covering every key exposed by the effective limits map.
 *
 * <p>Each limit row carries:
 * <ul>
 *   <li>{@code key} — the limit key (e.g. {@code max_apps})</li>
 *   <li>{@code current} — current usage (0 when not measured server-side)</li>
 *   <li>{@code cap} — effective cap (license override or default-tier value)</li>
 *   <li>{@code source} — {@code "license"} when the cap came from the license override map,
 *       {@code "default"} otherwise</li>
 * </ul>
 *
 * <p>{@code max_agents} is sourced from the in-memory {@link AgentRegistryService} since the
 * registry is not persisted; all other counts come from PostgreSQL via
 * {@link LicenseUsageReader#snapshot()}.</p>
 */
@RestController
@RequestMapping("/api/v1/admin/license/usage")
@PreAuthorize("hasRole('ADMIN')")
public class LicenseUsageController {

    private final LicenseGate gate;
    private final LicenseUsageReader reader;
    private final AgentRegistryService agents;
    private final LicenseService svc;
    private final LicenseRepository repo;

    public LicenseUsageController(LicenseGate gate,
                                  LicenseUsageReader reader,
                                  AgentRegistryService agents,
                                  LicenseService svc,
                                  LicenseRepository repo) {
        this.gate = gate;
        this.reader = reader;
        this.agents = agents;
        this.svc = svc;
        this.repo = repo;
    }

    @GetMapping
    public ResponseEntity<Map<String, Object>> get() {
        var state = gate.getState();
        var info = gate.getCurrent();
        var effective = gate.getEffectiveLimits();

        Map<String, Long> usage = new HashMap<>(reader.snapshot());
        usage.put("max_agents", (long) agents.liveCount());

        List<Map<String, Object>> limitRows = new ArrayList<>();
        for (var key : effective.values().keySet()) {
            Map<String, Object> row = new LinkedHashMap<>();
            row.put("key", key);
            row.put("current", usage.getOrDefault(key, 0L));
            row.put("cap", effective.get(key));
            row.put("source", info != null && info.limits().containsKey(key) ? "license" : "default");
            limitRows.add(row);
        }

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("state", state.name());
        body.put("expiresAt", info == null ? null : info.expiresAt().toString());
        body.put("daysRemaining", info == null ? null
                : Duration.between(Instant.now(), info.expiresAt()).toDays());
        body.put("gracePeriodDays", info == null ? 0 : info.gracePeriodDays());
        body.put("tenantId", info == null ? null : info.tenantId());
        body.put("label", info == null ? null : info.label());
        repo.findByTenantId(svc.getTenantId()).ifPresent(rec ->
                body.put("lastValidatedAt", rec.lastValidatedAt().toString()));
        body.put("message", LicenseMessageRenderer.forState(state, info, gate.getInvalidReason()));
        body.put("limits", limitRows);
        return ResponseEntity.ok(body);
    }
}
