/*
 * NIP-17 Private Direct Messages - Command Line Application
 *
 * This example demonstrates how to send NIP-17 private direct messages
 * using the Nostr Core Library.
 *
 * Usage:
 *   ./send_nip17_dm -r <recipient> -s <sender> [-R <relay>]... <message>
 *
 * Options:
 *   -r <recipient>: The recipient's public key (npub or hex)
 *   -s <sender>: The sender's private key (nsec or hex)
 *   -R <relay>: Relay URL to send to (can be specified multiple times)
 *   <message>: The message to send (must be the last argument)
 *
 * If no relays are specified, uses default relay.
 * If no sender key is provided, uses a default test key.
 *
 * Examples:
 *   ./send_nip17_dm -r npub1example... -s nsec1test... -R wss://relay1.com "Hello from NIP-17!"
 *   ./send_nip17_dm -r 4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa -s aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -R ws://localhost:8888 "config"
 */

#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L

#include "../nostr_core_lib/nostr_core/nostr_core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>

// Default test private key (for demonstration - DO NOT USE IN PRODUCTION)
#define DEFAULT_SENDER_NSEC "nsec12kgt0dv2k2safv6s32w8f89z9uw27e68hjaa0d66c5xvk70ezpwqncd045"

// Default relay for sending DMs
#define DEFAULT_RELAY "wss://relay.laantungir.net"

// Progress callback for publishing
void publish_progress_callback(const char* relay_url, const char* status,
                              const char* message, int success_count,
                              int total_relays, int completed_relays, void* user_data) {
    (void)user_data;

    if (relay_url) {
        printf("📡 [%s]: %s", relay_url, status);
        if (message) {
            printf(" - %s", message);
        }
        printf(" (%d/%d completed, %d successful)\n", completed_relays, total_relays, success_count);
    } else {
        printf("📡 PUBLISH COMPLETE: %d/%d successful\n", success_count, total_relays);
    }
}

/**
 * Convert npub or hex pubkey to hex format
 */
int convert_pubkey_to_hex(const char* input_pubkey, char* output_hex) {
    // Check if it's already hex (64 characters)
    if (strlen(input_pubkey) == 64) {
        // Assume it's already hex
        strcpy(output_hex, input_pubkey);
        return 0;
    }

    // Check if it's an npub (starts with "npub1")
    if (strncmp(input_pubkey, "npub1", 5) == 0) {
        // Convert npub to hex
        unsigned char pubkey_bytes[32];
        if (nostr_decode_npub(input_pubkey, pubkey_bytes) != 0) {
            fprintf(stderr, "Error: Invalid npub format\n");
            return -1;
        }
        nostr_bytes_to_hex(pubkey_bytes, 32, output_hex);
        return 0;
    }

    fprintf(stderr, "Error: Public key must be 64-character hex or valid npub\n");
    return -1;
}

/**
 * Convert nsec to private key bytes if needed
 */
int convert_nsec_to_private_key(const char* input_nsec, unsigned char* private_key) {
    // Check if it's already hex (64 characters)
    if (strlen(input_nsec) == 64) {
        // Convert hex to bytes
        if (nostr_hex_to_bytes(input_nsec, private_key, 32) != 0) {
            fprintf(stderr, "Error: Invalid hex private key\n");
            return -1;
        }
        return 0;
    }

    // Check if it's an nsec (starts with "nsec1")
    if (strncmp(input_nsec, "nsec1", 5) == 0) {
        // Convert nsec directly to private key bytes
        if (nostr_decode_nsec(input_nsec, private_key) != 0) {
            fprintf(stderr, "Error: Invalid nsec format\n");
            return -1;
        }
        return 0;
    }

    fprintf(stderr, "Error: Private key must be 64-character hex or valid nsec\n");
    return -1;
}

/**
 * Main function
 */
int main(int argc, char* argv[]) {
    char* recipient_key = NULL;
    char* sender_key = NULL;
    char** relays = NULL;
    int relay_count = 0;
    char* message = NULL;

    // Parse command line options
    int opt;
    while ((opt = getopt(argc, argv, "r:s:R:")) != -1) {
        switch (opt) {
            case 'r':
                recipient_key = optarg;
                break;
            case 's':
                sender_key = optarg;
                break;
            case 'R':
                relays = realloc(relays, (relay_count + 1) * sizeof(char*));
                relays[relay_count] = optarg;
                relay_count++;
                break;
            default:
                fprintf(stderr, "Usage: %s -r <recipient> -s <sender> [-R <relay>]... <message>\n", argv[0]);
                fprintf(stderr, "Options:\n");
                fprintf(stderr, "  -r <recipient>: The recipient's public key (npub or hex)\n");
                fprintf(stderr, "  -s <sender>: The sender's private key (nsec or hex)\n");
                fprintf(stderr, "  -R <relay>: Relay URL to send to (can be specified multiple times)\n");
                fprintf(stderr, "  <message>: The message to send (must be the last argument)\n");
                return 1;
        }
    }

    // Check for required arguments
    if (!recipient_key) {
        fprintf(stderr, "Error: Recipient key (-r) is required\n");
        return 1;
    }

    // Get message from remaining arguments
    if (optind >= argc) {
        fprintf(stderr, "Error: Message is required\n");
        return 1;
    }
    message = argv[optind];

    // Use default values if not provided
    if (!sender_key) {
        sender_key = DEFAULT_SENDER_NSEC;
    }
    if (relay_count == 0) {
        relays = malloc(sizeof(char*));
        relays[0] = DEFAULT_RELAY;
        relay_count = 1;
    }

    printf("🧪 NIP-17 Private Direct Message Sender\n");
    printf("======================================\n\n");

    // Initialize crypto
    if (nostr_init() != NOSTR_SUCCESS) {
        fprintf(stderr, "Failed to initialize crypto\n");
        free(relays);
        return 1;
    }

    // Convert recipient pubkey
    char recipient_pubkey_hex[65];
    if (convert_pubkey_to_hex(recipient_key, recipient_pubkey_hex) != 0) {
        free(relays);
        return 1;
    }

    // Convert sender private key
    unsigned char sender_privkey[32];
    if (convert_nsec_to_private_key(sender_key, sender_privkey) != 0) {
        free(relays);
        return 1;
    }

    // Derive sender public key for display
    unsigned char sender_pubkey_bytes[32];
    char sender_pubkey_hex[65];
    if (nostr_ec_public_key_from_private_key(sender_privkey, sender_pubkey_bytes) != 0) {
        fprintf(stderr, "Failed to derive sender public key\n");
        return 1;
    }
    nostr_bytes_to_hex(sender_pubkey_bytes, 32, sender_pubkey_hex);

    printf("📤 Sender: %s\n", sender_pubkey_hex);
    printf("📥 Recipient: %s\n", recipient_pubkey_hex);
    printf("💬 Message: %s\n", message);
    printf("🌐 Relays: ");
    for (int i = 0; i < relay_count; i++) {
        printf("%s", relays[i]);
        if (i < relay_count - 1) printf(", ");
    }
    printf("\n\n");

    // Create DM event
    printf("💬 Creating DM event...\n");
    const char* recipient_pubkeys[] = {recipient_pubkey_hex};
    cJSON* dm_event = nostr_nip17_create_chat_event(
        message,
        recipient_pubkeys,
        1,
        "NIP-17 CLI",  // subject
        NULL,          // no reply
        relays[0],     // relay hint (use first relay)
        sender_pubkey_hex
    );

    if (!dm_event) {
        fprintf(stderr, "Failed to create DM event\n");
        return 1;
    }

    printf("✅ Created DM event (kind 14)\n");

    // Send DM (create gift wraps)
    printf("🎁 Creating gift wraps...\n");
    cJSON* gift_wraps[10];  // Max 10 gift wraps
    int gift_wrap_count = nostr_nip17_send_dm(
        dm_event,
        recipient_pubkeys,
        1,
        sender_privkey,
        gift_wraps,
        10
    );

    cJSON_Delete(dm_event);  // Original DM event no longer needed

    if (gift_wrap_count <= 0) {
        fprintf(stderr, "Failed to create gift wraps\n");
        return 1;
    }

    printf("✅ Created %d gift wrap(s)\n", gift_wrap_count);

    // Publish the gift wrap to relays
    printf("\n📤 Publishing gift wrap to %d relay(s)...\n", relay_count);

    int success_count = 0;
    publish_result_t* publish_results = synchronous_publish_event_with_progress(
        (const char**)relays,
        relay_count,
        gift_wraps[0],  // Send the first gift wrap
        &success_count,
        10,  // 10 second timeout
        publish_progress_callback,
        NULL,  // no user data
        0,     // NIP-42 disabled
        NULL   // no private key for auth
    );

    if (!publish_results || success_count == 0) {
        fprintf(stderr, "\n❌ Failed to publish gift wrap to any relay (success_count: %d/%d)\n", success_count, relay_count);
        // Clean up gift wraps
        for (int i = 0; i < gift_wrap_count; i++) {
            cJSON_Delete(gift_wraps[i]);
        }
        if (publish_results) free(publish_results);
        free(relays);
        return 1;
    }

    printf("\n✅ Successfully published NIP-17 DM to %d/%d relay(s)!\n", success_count, relay_count);

    // Clean up
    free(publish_results);
    for (int i = 0; i < gift_wrap_count; i++) {
        cJSON_Delete(gift_wraps[i]);
    }
    free(relays);

    nostr_cleanup();

    printf("\n🎉 DM sent successfully! The recipient can now decrypt it using their private key.\n");

    return 0;
}