/*******************************************************************************
 * Copyright (c) 2026, Jan Koester jan.koester@gmx.net
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 * Neither the name of the <organization> nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

// netplus-certgen: CLI tool to generate self-signed TLS certificates
//
// Usage:
//   netplus-certgen [options]
//
// Options:
//   --cn <name>         Common Name (default: localhost)
//   --org <name>        Organization
//   --country <CC>      Country (2-letter code)
//   --bits <n>          RSA key size in bits (default: 2048)
//   --days <n>          Validity in days (default: 365)
//   --cert <path>       Certificate output path (default: cert.pem)
//   --key <path>        Private key output path (default: key.pem)
//   --der               Write DER format instead of PEM
//   --key-der <path>    Also write key in DER format to this path

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>

#include "../src/utils/certgen.h"

static void usage(const char *argv0) {
    std::cerr << "Usage: " << argv0 << " [options]\n"
              << "\nOptions:\n"
              << "  --cn <name>       Common Name (default: localhost)\n"
              << "  --org <name>      Organization\n"
              << "  --country <CC>    Country code\n"
              << "  --bits <n>        RSA key bits (default: 2048)\n"
              << "  --days <n>        Validity days (default: 365)\n"
              << "  --cert <path>     Certificate output (default: cert.pem)\n"
              << "  --key <path>      Key output (default: key.pem)\n"
              << "  --der             Output DER instead of PEM\n"
              << "  --key-der <path>  Also write key DER to this path\n"
              << "  -h, --help        Show this help\n";
}

int main(int argc, char *argv[]) {
    netplus::CertGenConfig cfg;
    std::string certPath = "cert.pem";
    std::string keyPath  = "key.pem";
    std::string keyDerPath;
    bool derMode = false;

    for (int i = 1; i < argc; ++i) {
        std::string arg = argv[i];
        if ((arg == "-h" || arg == "--help")) {
            usage(argv[0]);
            return 0;
        } else if (arg == "--cn" && i + 1 < argc) {
            cfg.commonName = argv[++i];
        } else if (arg == "--org" && i + 1 < argc) {
            cfg.organization = argv[++i];
        } else if (arg == "--country" && i + 1 < argc) {
            cfg.country = argv[++i];
        } else if (arg == "--bits" && i + 1 < argc) {
            cfg.rsaBits = static_cast<size_t>(std::atoi(argv[++i]));
        } else if (arg == "--days" && i + 1 < argc) {
            cfg.validDays = std::atoi(argv[++i]);
        } else if (arg == "--cert" && i + 1 < argc) {
            certPath = argv[++i];
        } else if (arg == "--key" && i + 1 < argc) {
            keyPath = argv[++i];
        } else if (arg == "--key-der" && i + 1 < argc) {
            keyDerPath = argv[++i];
        } else if (arg == "--der") {
            derMode = true;
        } else {
            std::cerr << "Unknown option: " << arg << "\n";
            usage(argv[0]);
            return 1;
        }
    }

    std::cerr << "Generating " << cfg.rsaBits << "-bit RSA key + self-signed certificate...\n"
              << "  CN=" << cfg.commonName << "  valid=" << cfg.validDays << " days\n";

    netplus::CertKeyPair pair;
    if (!netplus::generateSelfSignedCert(cfg, pair)) {
        std::cerr << "ERROR: Certificate generation failed.\n";
        return 1;
    }

    bool ok = true;
    if (derMode) {
        // DER output
        if (!certPath.empty()) {
            ok = netplus::writeDerFile(certPath, pair.certDer) && ok;
            if (ok) std::cerr << "  cert (DER): " << certPath << "\n";
        }
        if (!keyPath.empty()) {
            ok = netplus::writeDerFile(keyPath, pair.keyDer) && ok;
            if (ok) std::cerr << "  key  (DER): " << keyPath << "\n";
        }
    } else {
        // PEM output
        if (!certPath.empty()) {
            ok = netplus::writePemFile(certPath, pair.certPem) && ok;
            if (ok) std::cerr << "  cert (PEM): " << certPath << "\n";
        }
        if (!keyPath.empty()) {
            ok = netplus::writePemFile(keyPath, pair.keyPem) && ok;
            if (ok) std::cerr << "  key  (PEM): " << keyPath << "\n";
        }
    }

    // Optional extra key DER output (for QUIC stacks that need DER keys)
    if (!keyDerPath.empty()) {
        ok = netplus::writeDerFile(keyDerPath, pair.keyDer) && ok;
        if (ok) std::cerr << "  key  (DER): " << keyDerPath << "\n";
    }

    if (!ok) {
        std::cerr << "ERROR: Failed to write some output files.\n";
        return 1;
    }

    std::cerr << "Done.\n";
    return 0;
}
