#!/usr/bin/env node
/**
 * Generates password-generator defaults constants for all cross-platform clients.
 *
 * Input: core/models/src/defaults/PasswordGeneratorDefaults.ts
 * Outputs:
 *   - core/rust/src/password_generator/defaults.rs (Rust)
 *   - apps/server/Databases/AliasClientDb/Models/PasswordGeneratorDefaults.cs (C#)
 * 
 * Note: Typescript clients can import the constants directly from the distributed `@/utils/dist/core/models/vault`.
 */

const fs = require('fs');
const path = require('path');

const REPO_ROOT = path.join(__dirname, '../../..');
const TS_SOURCE = path.join(REPO_ROOT, 'core/models/src/defaults/PasswordGeneratorDefaults.ts');
const TS_SOURCE_REL = 'core/models/src/defaults/PasswordGeneratorDefaults.ts';

const RUST_OUTPUT = path.join(REPO_ROOT, 'core/rust/src/password_generator/defaults.rs');
const CS_OUTPUT = path.join(REPO_ROOT, 'apps/server/Databases/AliasClientDb/Models/PasswordGeneratorDefaults.cs');

/**
 * Parse the `export const NAME = VALUE;` lines (each with its leading single-line
 * JSDoc comment) out of the TypeScript source, preserving order.
 */
function parseConstants(source) {
  const constants = [];
  const lines = source.split('\n');
  let pendingDoc = null;

  for (const line of lines) {
    const trimmed = line.trim();

    // Single-line JSDoc comment: /** ... */
    if (trimmed.startsWith('/**') && trimmed.endsWith('*/')) {
      pendingDoc = trimmed.slice(3, -2).trim();
      continue;
    }

    const constMatch = line.match(/^\s*export const ([A-Z0-9_]+)\s*=\s*(\d+)\s*;/);
    if (constMatch) {
      constants.push({
        name: constMatch[1],
        value: Number(constMatch[2]),
        doc: pendingDoc || `${constMatch[1]}.`,
      });
      pendingDoc = null;
      continue;
    }

    // Any other non-blank line resets a dangling doc comment.
    if (line.trim() !== '') {
      pendingDoc = null;
    }
  }

  if (constants.length === 0) {
    throw new Error(`No 'export const ... = <number>;' constants found in ${TS_SOURCE_REL}`);
  }
  return constants;
}

/** SCREAMING_SNAKE_CASE -> PascalCase (DEFAULT_PASSWORD_LENGTH -> DefaultPasswordLength). */
function toPascalCase(name) {
  return name
    .toLowerCase()
    .split('_')
    .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
    .join('');
}

function generateRust(constants) {
  const header = `//! Client-facing defaults for the password/passphrase generator.
//!
//! @generated — do NOT edit this file directly. It is generated from
//! ${TS_SOURCE_REL} by core/models/scripts/generate-password-defaults.cjs.
//! Edit the TypeScript source and run 'core/models/build.sh' to regenerate.
`;

  const body = constants
    .map((c) => `/// ${c.doc}\npub const ${c.name}: u32 = ${c.value};`)
    .join('\n\n');

  return `${header}\n${body}\n`;
}

function generateCSharp(constants) {
  const header = `// <auto-generated />
// This file is auto-generated from ${TS_SOURCE_REL}
// Do not edit this file directly. Run 'core/models/build.sh' (or
// 'node core/models/scripts/generate-password-defaults.cjs') to regenerate.

#nullable enable

namespace AliasClientDb.Models;

/// <summary>
/// Password generator defaults shared across all AliasVault clients.
/// </summary>
public static class PasswordGeneratorDefaults
{`;

  const body = constants
    .map((c) => {
      const csName = toPascalCase(c.name);
      return `    /// <summary>\n    /// ${c.doc}\n    /// </summary>\n    public const int ${csName} = ${c.value};`;
    })
    .join('\n\n');

  return `${header}\n${body}\n}\n`;
}

function writeIfChanged(filePath, contents) {
  const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : null;
  if (existing === contents) {
    console.log(`  ✓ up to date: ${path.relative(REPO_ROOT, filePath)}`);
    return;
  }
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, contents);
  console.log(`  ✎ wrote:      ${path.relative(REPO_ROOT, filePath)}`);
}

function main() {
  const source = fs.readFileSync(TS_SOURCE, 'utf8');
  const constants = parseConstants(source);

  console.log(`Generating password-generator defaults from ${TS_SOURCE_REL}:`);
  console.log(`  ${constants.map((c) => `${c.name}=${c.value}`).join(', ')}`);

  writeIfChanged(RUST_OUTPUT, generateRust(constants));
  writeIfChanged(CS_OUTPUT, generateCSharp(constants));
}

main();
