package ru.zetit.bridgeandjoins.crypto;

import io.grpc.Server;
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
import io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup;
import io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerDomainSocketChannel;
import io.grpc.netty.shaded.io.netty.channel.unix.DomainSocketAddress;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.logging.Logger;

/**
 * Точка входа crypto-service.
 *
 * Слушает Unix Domain Socket по пути из BJ_CRYPTO_SOCKET
 * (по умолчанию /run/bj/crypto.sock). UDS вместо TCP — минимальная
 * задержка и изоляция от сети.
 *
 * Провайдер выбирается через BJ_CRYPTO_PROVIDER:
 *   - "validata" — АПК «Валидата Клиент L» (через Pki1.LocalIface);
 *   - что-либо ещё или пусто — stub (gRPC жив, реальная криптография
 *     отключена; используется на дев-стендах).
 *
 * Профиль Валидаты задаётся через BJ_VALIDATA_PROFILE (имя из
 * pki1.conf или ПК «Справочник сертификатов»). Если пусто —
 * инициализация в режиме VCERT_InitMinimal (хэш, Base64, RAND).
 */
public final class CryptoServer {

    private static final Logger LOG = Logger.getLogger(CryptoServer.class.getName());
    private static final String DEFAULT_SOCKET = "/run/bj/crypto.sock";

    private CryptoServer() { /* utility */ }

    public static void main(String[] args) throws IOException, InterruptedException {
        String socketPath = System.getenv().getOrDefault("BJ_CRYPTO_SOCKET", DEFAULT_SOCKET);
        String provider = System.getenv().getOrDefault("BJ_CRYPTO_PROVIDER", "stub");

        Files.createDirectories(Path.of(socketPath).getParent());
        Files.deleteIfExists(Path.of(socketPath));

        KeystoreProvider keystore = KeystoreProvider.byName(provider);
        LOG.info("crypto-service: провайдер " + keystore.name() + " — " + keystore.message());

        VerifyHandler verifyHandler = new VerifyHandler(keystore);
        SignHandler signHandler = new SignHandler(keystore);
        HealthHandler healthHandler = new HealthHandler(keystore);
        ActivateHandler activateHandler = new ActivateHandler(keystore);
        ShutdownHandler shutdownHandler = new ShutdownHandler();

        CryptoServiceImpl service = new CryptoServiceImpl(verifyHandler, signHandler,
                healthHandler, activateHandler, shutdownHandler);

        Server server = NettyServerBuilder
                .forAddress(new DomainSocketAddress(socketPath))
                .channelType(EpollServerDomainSocketChannel.class)
                .bossEventLoopGroup(new EpollEventLoopGroup(1))
                .workerEventLoopGroup(new EpollEventLoopGroup())
                .addService(service)
                .build()
                .start();

        LOG.info("crypto-service: UDS " + socketPath + ", provider=" + keystore.name()
                + ", ready=" + keystore.ready());

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            LOG.info("crypto-service: graceful shutdown");
            server.shutdown();
            keystore.close();
        }));

        server.awaitTermination();
    }
}
