#!/usr/bin/env node
/**
 * Fetches kinds.json from the nostr library and generates eventKinds.js
 * Run: node scripts/fetch-kinds.js
 */

import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { writeFileSync, existsSync } from 'fs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const KINDS_URL = 'https://git.mleku.dev/mleku/nostr/raw/branch/main/encoders/kind/kinds.json';
const OUTPUT_PATH = join(__dirname, '..', 'src', 'eventKinds.js');

async function fetchKinds() {
  console.log(`Fetching kinds from ${KINDS_URL}...`);

  try {
    const response = await fetch(KINDS_URL, { timeout: 10000 });
    if (!response.ok) {
      throw new Error(`HTTP ${response.status} ${response.statusText}`);
    }

    const data = await response.json();
    console.log(`Fetched ${Object.keys(data.kinds).length} kinds (version: ${data.version})`);
    return data;
  } catch (error) {
    // Check if we have an existing eventKinds.js we can use
    if (existsSync(OUTPUT_PATH)) {
      console.warn(`Warning: Could not fetch kinds.json (${error.message})`);
      console.log(`Using existing ${OUTPUT_PATH}`);
      return null; // Signal to skip generation
    }
    throw new Error(`Failed to fetch kinds.json and no existing file: ${error.message}`);
  }
}

function generateEventKinds(data) {
  const kinds = [];

  for (const [kindNum, info] of Object.entries(data.kinds)) {
    const k = parseInt(kindNum, 10);

    // Determine classification
    let isReplaceable = false;
    let isAddressable = false;
    let isEphemeral = false;

    if (info.classification === 'replaceable' || k === 0 || k === 3 ||
        (k >= data.ranges.replaceable.start && k < data.ranges.replaceable.end)) {
      isReplaceable = true;
    } else if (info.classification === 'parameterized' ||
        (k >= data.ranges.parameterized.start && k <= data.ranges.parameterized.end)) {
      isAddressable = true;
    } else if (info.classification === 'ephemeral' ||
        (k >= data.ranges.ephemeral.start && k < data.ranges.ephemeral.end)) {
      isEphemeral = true;
    }

    const entry = {
      kind: k,
      name: info.name,
      description: info.description,
      nip: info.nip || null,
    };

    if (isReplaceable) entry.isReplaceable = true;
    if (isAddressable) entry.isAddressable = true;
    if (isEphemeral) entry.isEphemeral = true;
    if (info.deprecated) entry.deprecated = true;
    if (info.spec) entry.spec = info.spec;

    // Add basic template
    entry.template = {
      kind: k,
      content: "",
      tags: []
    };

    // Add d tag for addressable events
    if (isAddressable) {
      entry.template.tags = [["d", "identifier"]];
    }

    kinds.push(entry);
  }

  // Sort by kind number
  kinds.sort((a, b) => a.kind - b.kind);

  return kinds;
}

function generateJS(kinds, data) {
  return `/**
 * Nostr Event Kinds Database
 * Auto-generated from ${KINDS_URL}
 * Version: ${data.version}
 * Source: ${data.source}
 *
 * DO NOT EDIT - This file is auto-generated by scripts/fetch-kinds.js
 */

export const eventKinds = ${JSON.stringify(kinds, null, 2)};

// Kind ranges for classification
export const kindRanges = ${JSON.stringify(data.ranges, null, 2)};

// Privileged kinds (require auth)
export const privilegedKinds = ${JSON.stringify(data.privileged)};

// Directory kinds (public discovery)
export const directoryKinds = ${JSON.stringify(data.directory)};

// Kind aliases
export const kindAliases = ${JSON.stringify(data.aliases, null, 2)};

// Helper function to get event kind by number
export function getEventKind(kindNumber) {
  return eventKinds.find(k => k.kind === kindNumber);
}

// Alias for compatibility
export function getKindInfo(kind) {
  return getEventKind(kind);
}

export function getKindName(kind) {
  const info = getEventKind(kind);
  return info ? info.name : \`Kind \${kind}\`;
}

// Helper function to search event kinds by name or description
export function searchEventKinds(query) {
  const lowerQuery = query.toLowerCase();
  return eventKinds.filter(k =>
    k.name.toLowerCase().includes(lowerQuery) ||
    k.description.toLowerCase().includes(lowerQuery) ||
    k.kind.toString().includes(query)
  );
}

// Helper function to get all event kinds grouped by category
export function getEventKindsByCategory() {
  return {
    regular: eventKinds.filter(k => k.kind < 10000 && !k.isReplaceable),
    replaceable: eventKinds.filter(k => k.isReplaceable),
    ephemeral: eventKinds.filter(k => k.isEphemeral),
    addressable: eventKinds.filter(k => k.isAddressable)
  };
}

// Helper function to create a template event with current timestamp
export function createTemplateEvent(kindNumber, userPubkey = null) {
  const kindInfo = getEventKind(kindNumber);
  if (!kindInfo) {
    return {
      kind: kindNumber,
      content: "",
      tags: [],
      created_at: Math.floor(Date.now() / 1000),
      pubkey: userPubkey || "<your_pubkey_here>"
    };
  }

  return {
    ...kindInfo.template,
    created_at: Math.floor(Date.now() / 1000),
    pubkey: userPubkey || "<your_pubkey_here>"
  };
}

export function isReplaceable(kind) {
  if (kind === 0 || kind === 3) return true;
  return kind >= ${data.ranges.replaceable.start} && kind < ${data.ranges.replaceable.end};
}

export function isEphemeral(kind) {
  return kind >= ${data.ranges.ephemeral.start} && kind < ${data.ranges.ephemeral.end};
}

export function isAddressable(kind) {
  return kind >= ${data.ranges.parameterized.start} && kind <= ${data.ranges.parameterized.end};
}

export function isPrivileged(kind) {
  return privilegedKinds.includes(kind);
}

// Export kind categories for filtering in UI
export const kindCategories = [
  { id: "all", name: "All Kinds", filter: () => true },
  { id: "regular", name: "Regular Events (0-9999)", filter: k => k.kind < 10000 && !k.isReplaceable },
  { id: "replaceable", name: "Replaceable (10000-19999)", filter: k => k.isReplaceable },
  { id: "ephemeral", name: "Ephemeral (20000-29999)", filter: k => k.isEphemeral },
  { id: "addressable", name: "Addressable (30000-39999)", filter: k => k.isAddressable },
  { id: "social", name: "Social", filter: k => [0, 1, 3, 6, 7].includes(k.kind) },
  { id: "messaging", name: "Messaging", filter: k => [4, 9, 10, 11, 12, 14, 15, 40, 41, 42].includes(k.kind) },
  { id: "lists", name: "Lists", filter: k => k.name.toLowerCase().includes("list") || k.name.toLowerCase().includes("set") },
  { id: "marketplace", name: "Marketplace", filter: k => [30017, 30018, 30019, 30020, 1021, 1022, 30402, 30403].includes(k.kind) },
  { id: "lightning", name: "Lightning/Zaps", filter: k => [9734, 9735, 9041, 9321, 7374, 7375, 7376].includes(k.kind) },
  { id: "media", name: "Media", filter: k => [20, 21, 22, 1063, 1222, 1244].includes(k.kind) },
  { id: "git", name: "Git/Code", filter: k => [818, 1337, 1617, 1618, 1619, 1621, 1622, 30617, 30618].includes(k.kind) },
  { id: "calendar", name: "Calendar", filter: k => [31922, 31923, 31924, 31925].includes(k.kind) },
  { id: "groups", name: "Groups", filter: k => (k.kind >= 9000 && k.kind <= 9030) || (k.kind >= 39000 && k.kind <= 39009) },
];
`;
}

async function main() {
  try {
    const data = await fetchKinds();

    // If fetchKinds returned null, we're using the existing file
    if (data === null) {
      console.log('Skipping generation, using existing eventKinds.js');
      return;
    }

    const kinds = generateEventKinds(data);
    const js = generateJS(kinds, data);

    writeFileSync(OUTPUT_PATH, js);
    console.log(`Generated ${OUTPUT_PATH} with ${kinds.length} kinds`);
  } catch (error) {
    console.error('Error:', error.message);
    process.exit(1);
  }
}

main();
