package com.cameleer.server.app;

import com.cameleer.server.core.agent.AgentRegistryService;
import com.cameleer.server.core.license.LicenseGate;
import com.cameleer.server.core.license.LicenseInfo;
import com.cameleer.server.core.security.JwtService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Test utility for creating JWT-authenticated requests in integration tests.
 * <p>
 * Registers a test agent and issues a JWT access token that can be used
 * to authenticate against protected endpoints.
 */
@Component
public class TestSecurityHelper {

    private final JwtService jwtService;
    private final AgentRegistryService agentRegistryService;
    private final LicenseGate licenseGate;

    @Autowired
    public TestSecurityHelper(JwtService jwtService,
                              AgentRegistryService agentRegistryService,
                              LicenseGate licenseGate) {
        this.jwtService = jwtService;
        this.agentRegistryService = agentRegistryService;
        this.licenseGate = licenseGate;
    }

    /**
     * Loads a synthetic, signature-bypassing license into {@link LicenseGate} so the test can
     * exercise paths that would otherwise be rejected by default-tier caps. The license is
     * always-ACTIVE (1 day from now, no grace) and limits are merged over defaults — only
     * supply the keys you want to lift. Use this from {@code @BeforeEach} in ITs that need to
     * create more than the default-tier allowance of envs/apps/users/etc.
     */
    public void installSyntheticUnsignedLicense(Map<String, Integer> caps) {
        LicenseInfo info = new LicenseInfo(
                UUID.randomUUID(),
                "default",
                "test-license",
                Map.copyOf(caps),
                Instant.now(),
                Instant.now().plus(1, ChronoUnit.DAYS),
                0);
        licenseGate.load(info);
    }

    /** Clears any test license previously installed via {@link #installSyntheticUnsignedLicense}. */
    public void clearTestLicense() {
        licenseGate.clear();
    }

    /**
     * Registers a test agent and returns a valid JWT access token with AGENT role.
     */
    public String registerTestAgent(String instanceId) {
        agentRegistryService.register(instanceId, instanceId, "test-group", "default", "1.0", List.of(), Map.of());
        return jwtService.createAccessToken(instanceId, "test-group", List.of("AGENT"));
    }

    /**
     * Returns a valid JWT access token with the given roles (no agent registration).
     */
    public String createToken(String subject, String application, List<String> roles) {
        return jwtService.createAccessToken(subject, application, roles);
    }

    /**
     * Returns a valid JWT access token with OPERATOR role.
     */
    public String operatorToken() {
        // Subject must start with "user:" for JwtAuthenticationFilter to treat it as a UI user token
        return jwtService.createAccessToken("user:test-operator", "user", List.of("OPERATOR"));
    }

    /**
     * Returns a valid JWT access token with ADMIN role.
     */
    public String adminToken() {
        return jwtService.createAccessToken("user:test-admin", "user", List.of("ADMIN"));
    }

    /**
     * Returns a valid JWT access token with VIEWER role.
     */
    public String viewerToken() {
        return jwtService.createAccessToken("user:test-viewer", "user", List.of("VIEWER"));
    }

    /**
     * Returns HttpHeaders with JWT Bearer authorization, protocol version, and JSON content type.
     */
    public HttpHeaders authHeaders(String jwt) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + jwt);
        headers.set("X-Cameleer-Protocol-Version", "1");
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
    }

    /**
     * Returns HttpHeaders with JWT Bearer authorization and protocol version (no content type).
     */
    public HttpHeaders authHeadersNoBody(String jwt) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + jwt);
        headers.set("X-Cameleer-Protocol-Version", "1");
        return headers;
    }

    /**
     * Returns HttpHeaders with ADMIN JWT Bearer authorization, protocol version, and JSON content type.
     */
    public HttpHeaders adminHeaders() {
        return authHeaders(adminToken());
    }

    /**
     * Returns HttpHeaders with bootstrap token authorization, protocol version, and JSON content type.
     */
    public HttpHeaders bootstrapHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer test-bootstrap-token");
        headers.set("X-Cameleer-Protocol-Version", "1");
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
    }
}
