/**
 * timmy-identity.ts — Timmy's persistent Nostr identity.
 *
 * Loads a secp256k1 keypair from TIMMY_NOSTR_NSEC env var at boot.
 * If the env var is absent, generates an ephemeral keypair and logs
 * a warning instructing the operator to persist it.
 *
 * Exports `timmyIdentityService` singleton with:
 *   .npub      — bech32 public key (npub1...)
 *   .nsec      — bech32 private key (nsec1...) — never log this
 *   .pubkeyHex — raw 64-char hex pubkey
 *   .sign(template)     — finalises and signs a Nostr event template
 *   .encryptDm(recipientPubkeyHex, plaintext) — NIP-04 encrypt
 */

import { generateSecretKey, getPublicKey, finalizeEvent, nip19, nip04 } from "nostr-tools";
import type { EventTemplate, NostrEvent } from "nostr-tools";
import { makeLogger } from "./logger.js";

const logger = makeLogger("timmy-identity");

function loadOrGenerate(): { sk: Uint8Array; nsec: string; npub: string; pubkeyHex: string } {
  const raw = process.env["TIMMY_NOSTR_NSEC"];
  if (raw && raw.startsWith("nsec1")) {
    try {
      const decoded = nip19.decode(raw);
      if (decoded.type !== "nsec") throw new Error("not nsec type");
      const sk = decoded.data as Uint8Array;
      const pubkeyHex = getPublicKey(sk);
      const npub = nip19.npubEncode(pubkeyHex);
      logger.info("timmy identity loaded from env", { npub });
      return { sk, nsec: raw, npub, pubkeyHex };
    } catch (err) {
      logger.warn("TIMMY_NOSTR_NSEC is set but could not be decoded — generating ephemeral key", {
        error: err instanceof Error ? err.message : String(err),
      });
    }
  }

  const sk = generateSecretKey();
  const pubkeyHex = getPublicKey(sk);
  const nsec = nip19.nsecEncode(sk);
  const npub = nip19.npubEncode(pubkeyHex);

  logger.warn(
    "TIMMY_NOSTR_NSEC not set — generated ephemeral Nostr identity. " +
    "Set this env var permanently to preserve Timmy's identity across restarts.",
    { npub },
  );

  return { sk, nsec, npub, pubkeyHex };
}

class TimmyIdentityService {
  readonly npub: string;
  readonly nsec: string;
  readonly pubkeyHex: string;
  private readonly _sk: Uint8Array;

  constructor() {
    const identity = loadOrGenerate();
    this.npub = identity.npub;
    this.nsec = identity.nsec;
    this.pubkeyHex = identity.pubkeyHex;
    this._sk = identity.sk;
  }

  sign(template: EventTemplate): NostrEvent {
    return finalizeEvent(template, this._sk);
  }

  async encryptDm(recipientPubkeyHex: string, plaintext: string): Promise<string> {
    return nip04.encrypt(this._sk, recipientPubkeyHex, plaintext);
  }
}

export const timmyIdentityService = new TimmyIdentityService();
