/*
 * voicecat-admin — offline account management tool.
 *
 * Directly manipulates {data_dir}/voicecat.db without a running server.
 * Usage:
 *   voicecat-admin [--data-dir <path>] account add    <username> [--admin] [--password <p>]
 *   voicecat-admin [--data-dir <path>] account reset  <username> [--password <p>]
 *   voicecat-admin [--data-dir <path>] account del    <username>
 *   voicecat-admin [--data-dir <path>] account list
 */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <optional>
#include <string>

#ifdef VOICECAT_HAS_NET

#include "db.h"
using namespace voicecat::server;

static void print_usage(const char* argv0) {
    std::fprintf(stderr,
        "Usage:\n"
        "  %s [--data-dir <path>] account add   <user> [--admin] [--password <p>]\n"
        "  %s [--data-dir <path>] account reset <user> [--password <p>]\n"
        "  %s [--data-dir <path>] account del   <user>\n"
        "  %s [--data-dir <path>] account list\n",
        argv0, argv0, argv0, argv0);
}

static std::string read_password_stdin(const char* prompt) {
    std::fprintf(stderr, "%s: ", prompt);
    std::fflush(stderr);
    std::string pw;
    std::getline(std::cin, pw);
    return pw;
}

int main(int argc, char** argv) {
    std::string data_dir = "voicecat-data";
    int i = 1;

    // Parse --data-dir
    if (i < argc && std::strcmp(argv[i], "--data-dir") == 0) {
        if (++i >= argc) { std::fprintf(stderr, "Missing argument to --data-dir\n"); return 1; }
        data_dir = argv[i++];
    }

    if (i >= argc || std::strcmp(argv[i], "account") != 0) {
        print_usage(argv[0]); return 1;
    }
    ++i;  // skip "account"

    if (i >= argc) { print_usage(argv[0]); return 1; }
    std::string subcmd = argv[i++];

    std::string db_path = data_dir + "/voicecat.db";
    Database db(db_path);
    std::string error;
    if (!db.open(error)) {
        std::fprintf(stderr, "Failed to open database %s: %s\n", db_path.c_str(), error.c_str());
        return 1;
    }

    if (subcmd == "list") {
        auto accounts = db.list_accounts();
        if (accounts.empty()) {
            std::printf("(no accounts)\n");
        } else {
            std::printf("%-20s  %-5s  %s\n", "username", "admin", "created_at");
            std::printf("%-20s  %-5s  %s\n", "--------", "-----", "----------");
            for (auto& acc : accounts) {
                std::printf("%-20s  %-5s  %lld\n",
                    acc.username.c_str(),
                    acc.is_admin ? "yes" : "no",
                    static_cast<long long>(acc.created_at));
            }
        }
        return 0;
    }

    if (subcmd == "add") {
        if (i >= argc) { std::fprintf(stderr, "add requires a username\n"); return 1; }
        std::string username = argv[i++];
        bool is_admin = false;
        std::optional<std::string> password;

        while (i < argc) {
            if (std::strcmp(argv[i], "--admin") == 0) { is_admin = true; ++i; }
            else if (std::strcmp(argv[i], "--password") == 0) {
                if (++i >= argc) { std::fprintf(stderr, "Missing argument to --password\n"); return 1; }
                password = argv[i++];
            } else { std::fprintf(stderr, "Unknown option: %s\n", argv[i]); return 1; }
        }

        if (!password) password = read_password_stdin("Password");
        if (password->empty()) { std::fprintf(stderr, "Password must not be empty\n"); return 1; }

        auto acc = db.create_account(username, *password, is_admin, error);
        if (!acc) { std::fprintf(stderr, "Failed to create account: %s\n", error.c_str()); return 1; }
        std::printf("Created account '%s'%s (id=%lld)\n",
            acc->username.c_str(), is_admin ? " [admin]" : "",
            static_cast<long long>(acc->id));
        return 0;
    }

    if (subcmd == "reset") {
        if (i >= argc) { std::fprintf(stderr, "reset requires a username\n"); return 1; }
        std::string username = argv[i++];
        std::optional<std::string> password;

        while (i < argc) {
            if (std::strcmp(argv[i], "--password") == 0) {
                if (++i >= argc) { std::fprintf(stderr, "Missing argument to --password\n"); return 1; }
                password = argv[i++];
            } else { std::fprintf(stderr, "Unknown option: %s\n", argv[i]); return 1; }
        }

        if (!password) password = read_password_stdin("New password");
        if (password->empty()) { std::fprintf(stderr, "Password must not be empty\n"); return 1; }

        if (!db.reset_password(username, *password, error)) {
            std::fprintf(stderr, "Failed: %s\n", error.c_str()); return 1;
        }
        std::printf("Password reset for '%s'\n", username.c_str());
        return 0;
    }

    if (subcmd == "del") {
        if (i >= argc) { std::fprintf(stderr, "del requires a username\n"); return 1; }
        std::string username = argv[i++];
        if (!db.delete_account(username, error)) {
            std::fprintf(stderr, "Failed: %s\n", error.c_str()); return 1;
        }
        std::printf("Deleted account '%s'\n", username.c_str());
        return 0;
    }

    std::fprintf(stderr, "Unknown subcommand: %s\n", subcmd.c_str());
    print_usage(argv[0]);
    return 1;
}

#else  // !VOICECAT_HAS_NET

int main() {
    std::fprintf(stderr, "voicecat-admin requires VOICECAT_HAS_NET (build with dev preset)\n");
    return 1;
}

#endif  // VOICECAT_HAS_NET
