package com.cameleer.license.minter.cli;

import com.cameleer.server.core.license.LicenseValidator;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.Base64;

import static org.assertj.core.api.Assertions.assertThat;

class LicenseMinterCliTest {

    @TempDir Path tmp;

    @Test
    void mints_validToken_validatorAccepts() throws Exception {
        KeyPair kp = KeyPairGenerator.getInstance("Ed25519").generateKeyPair();
        Path priv = tmp.resolve("priv.b64");
        Path pub = tmp.resolve("pub.b64");
        Files.writeString(priv, Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded()));
        Files.writeString(pub, Base64.getEncoder().encodeToString(kp.getPublic().getEncoded()));
        Path out = tmp.resolve("license.tok");

        int code = LicenseMinterCli.run(new String[]{
                "--private-key=" + priv,
                "--tenant=acme",
                "--label=ACME",
                "--expires=2099-12-31",
                "--grace-days=30",
                "--max-apps=50",
                "--output=" + out
        });

        assertThat(code).isEqualTo(0);
        String token = Files.readString(out).trim();
        var info = new LicenseValidator(Files.readString(pub).trim(), "acme").validate(token);
        assertThat(info.tenantId()).isEqualTo("acme");
        assertThat(info.limits().get("max_apps")).isEqualTo(50);
        assertThat(info.gracePeriodDays()).isEqualTo(30);
    }

    @Test
    void unknownFlag_failsFast() {
        int code = LicenseMinterCli.run(new String[]{"--frobnicate=yes"});
        assertThat(code).isNotZero();
    }

    @Test
    void verify_happyPath_succeeds() throws Exception {
        KeyPair kp = KeyPairGenerator.getInstance("Ed25519").generateKeyPair();
        Path priv = tmp.resolve("priv.b64");
        Path pub = tmp.resolve("pub.b64");
        Files.writeString(priv, Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded()));
        Files.writeString(pub, Base64.getEncoder().encodeToString(kp.getPublic().getEncoded()));
        Path out = tmp.resolve("license.tok");

        int code = LicenseMinterCli.run(new String[]{
                "--private-key=" + priv,
                "--public-key=" + pub,
                "--tenant=acme",
                "--expires=2099-12-31",
                "--output=" + out,
                "--verify"
        });

        assertThat(code).isEqualTo(0);
        assertThat(out).exists();
    }

    @Test
    void verify_wrongPublicKey_deletesOutputAndExitsNonZero() throws Exception {
        KeyPair signing = KeyPairGenerator.getInstance("Ed25519").generateKeyPair();
        KeyPair other = KeyPairGenerator.getInstance("Ed25519").generateKeyPair();
        Path priv = tmp.resolve("priv.b64");
        Path pub = tmp.resolve("pub.b64");
        Files.writeString(priv, Base64.getEncoder().encodeToString(signing.getPrivate().getEncoded()));
        Files.writeString(pub, Base64.getEncoder().encodeToString(other.getPublic().getEncoded()));
        Path out = tmp.resolve("license.tok");

        int code = LicenseMinterCli.run(new String[]{
                "--private-key=" + priv,
                "--public-key=" + pub,
                "--tenant=acme",
                "--expires=2099-12-31",
                "--output=" + out,
                "--verify"
        });

        assertThat(code).isNotZero();
        assertThat(out).doesNotExist();
    }

    @Test
    void verify_withoutPublicKey_fails() throws Exception {
        KeyPair kp = KeyPairGenerator.getInstance("Ed25519").generateKeyPair();
        Path priv = tmp.resolve("priv.b64");
        Files.writeString(priv, Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded()));

        int code = LicenseMinterCli.run(new String[]{
                "--private-key=" + priv,
                "--tenant=acme",
                "--expires=2099-12-31",
                "--verify"
        });

        assertThat(code).isNotZero();
    }
}
