#!/usr/bin/env node

const readline = require('readline');
const { spawn } = require('child_process');
const { join, resolve } = require('path');
const fs = require('fs');

// Find the root directory of the project
function findProjectRoot() {
  let currentDir = __dirname;
  while (!fs.existsSync(join(currentDir, 'nx.json'))) {
    const parentDir = resolve(currentDir, '..');
    if (parentDir === currentDir) {
      // We've reached the root of the filesystem
      return process.cwd();
    }
    currentDir = parentDir;
  }
  return currentDir;
}

const projectRoot = findProjectRoot();

// Function to validate module and entity names
function validateName(name) {
  // Ensure name is not empty
  if (!name || name.trim() === '') {
    return 'Name cannot be empty.';
  }

  // Ensure name is not just a number
  if (/^\d+$/.test(name)) {
    return 'Name cannot be just a number. Please include at least one letter.';
  }

  // Less restrictive validation that allows non-Latin characters
  // Just check for spaces, special characters, and make sure it starts with a letter or non-Latin character
  if (/^[^a-zA-Z\p{L}]|\s|[^\w\p{L}]/u.test(name)) {
    return 'Name must start with a letter and cannot contain spaces or special characters.';
  }

  return null; // No error
}

// Check for --dryRun flag at the beginning
const isDryRun = process.argv.includes('--dryRun');

// Create an interface for readline
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

// Define widget catalog - copied from widget-catalog.ts
const widgetCatalog = {
  text: 'text-editor',
  password: 'password-editor',
  largeText: 'large-text-editor',
  richText: 'rich-text-editor',
  number: 'number-editor',
  numberUnit: 'number-unit-editor',
  select: 'select-editor',
  checkbox: 'checkbox-editor',
  toggle: 'toggle-editor',
  dateTime: 'date-time-editor',
  color: 'color-editor',
  contact: 'contact-editor',
  tagable: 'tagable-editor',
  file: 'file',
  gallery: 'gallery',
  signature: 'signature',
  map: 'map',
  lookup: 'lookup-editor',
  selectionList: 'selection-list-editor',
  table: 'table-editor',
  qrcode: 'qrcode',
  schedulerPicker: 'scheduler-picker',
  singleFileBox: 'single-file-box-editor',
  metaData: 'meta-data-editor',
};

// Define widget to data type mapping
const widgetToDataType = {
  'text-editor': 'string',
  'password-editor': 'string',
  'large-text-editor': 'string',
  'rich-text-editor': 'string',
  'number-editor': 'number',
  'number-unit-editor': 'number',
  'select-editor': 'object',
  'checkbox-editor': 'boolean',
  'toggle-editor': 'boolean',
  'date-time-editor': 'date',
  'color-editor': 'string',
  'contact-editor': 'object',
  'tagable-editor': 'string',
  file: 'object',
  gallery: 'object',
  signature: 'string',
  map: 'object',
  'lookup-editor': 'object',
  'selection-list-editor': 'array',
  'table-editor': 'array',
  qrcode: 'string',
  'single-file-box-editor': 'object',
  'meta-data-editor': 'object',
};

// Widget groups for better display
const widgetGroups = {
  Basic: ['text-editor', 'large-text-editor', 'rich-text-editor', 'number-editor', 'checkbox-editor', 'toggle-editor'],
  Input: ['password-editor', 'date-time-editor', 'color-editor'],
  Complex: ['select-editor', 'lookup-editor', 'selection-list-editor', 'table-editor'],
  Media: ['file', 'gallery', 'signature', 'map', 'qrcode'],
};

// Define default colSpan based on widget type
const widgetToColSpan = {
  'text-editor': 6,
  'password-editor': 6,
  'large-text-editor': 12,
  'rich-text-editor': 12,
  'number-editor': 4,
  'number-unit-editor': 6,
  'select-editor': 6,
  'checkbox-editor': 4,
  'toggle-editor': 4,
  'date-time-editor': 6,
  'color-editor': 4,
  'contact-editor': 8,
  'tagable-editor': 8,
  file: 6,
  gallery: 12,
  signature: 8,
  map: 12,
  'lookup-editor': 6,
  'selection-list-editor': 8,
  'table-editor': 12,
  qrcode: 6,
  'single-file-box-editor': 6,
  'meta-data-editor': 8,
};

// Create data object to store all user input
const data = {
  moduleName: '',
  name: '',
  properties: [],
  dataTypes: [],
  required: [],
  colSpans: [],
  orders: [],
  widgets: [], // Used locally but not passed to NX generator
  icon: 'fa-light fa-default',
  enableSorts: [],
  enableFilters: [],
  enableInlineFilters: [],
  inColumn: [], // اضافه کردن آرایه جدید برای ذخیره وضعیت نمایش در ستون
};

// Run the prompts in sequence
async function runPrompts() {
  console.log('\n=== AcoreX Platform Interactive Entity Generator ===\n');

  // Get module name with validation
  while (true) {
    data.moduleName = await askQuestion('Module name: ');
    const error = validateName(data.moduleName);
    if (error) {
      console.log(`Error: ${error}`);
    } else {
      break;
    }
  }

  // Get entity name with validation
  while (true) {
    data.name = await askQuestion('Entity name: ');
    const error = validateName(data.name);
    if (error) {
      console.log(`Error: ${error}`);
    } else {
      break;
    }
  }

  // Get properties
  console.log('\nEnter properties (type "done" when finished):');
  let propCount = 1;
  while (true) {
    const prop = await askQuestion(`Property ${propCount}: `);
    if (prop.toLowerCase() === 'done') {
      break;
    }
    data.properties.push(prop);

    // Get widget for this property
    const widget = await selectWidget(`Select widget for "${prop}": `);
    data.widgets.push(widget);

    // Automatically determine data type based on widget
    const dataType = widgetToDataType[widget] || 'string';
    data.dataTypes.push(dataType);

    // Ask if this property is required
    const isRequired = await askQuestion(`Is "${prop}" required? (y/n): `, 'n');
    if (isRequired.toLowerCase() === 'y') {
      data.required.push(prop);
    }

    // Ask if this property should be displayed in columns
    const showInColumn = await askQuestion(`Show "${prop}" in table columns? (y/n): `, 'y');
    data.inColumn.push(showInColumn.toLowerCase() === 'y' ? 'true' : 'false');

    // Get colSpan for this property (1-12)
    const defaultColSpan = widgetToColSpan[widget] || 6;
    const colSpan = await askQuestion(`Column span for "${prop}" (1-12): `, defaultColSpan.toString());
    data.colSpans.push(parseInt(colSpan));

    // Get order for this property
    const defaultOrder = propCount; // Default order is sequential
    const order = await askQuestion(
      `Display order for "${prop}" (default: ${defaultOrder}): `,
      defaultOrder.toString(),
    );
    data.orders.push(parseInt(order));

    // Ask about sort
    const enableSort = await askQuestion(`Enable sorting for "${prop}"? (y/n): `, 'y');
    data.enableSorts.push(enableSort.toLowerCase() === 'y' ? 'true' : 'false');

    // Ask about filter
    const enableFilter = await askQuestion(`Enable filtering for "${prop}"? (y/n): `, 'y');
    data.enableFilters.push(enableFilter.toLowerCase() === 'y' ? 'true' : 'false');

    // Ask about inline filter
    const enableInlineFilter = await askQuestion(`Enable inline filtering for "${prop}"? (y/n): `, 'n');
    data.enableInlineFilters.push(enableInlineFilter.toLowerCase() === 'y' ? 'true' : 'false');

    propCount++;
  }

  // Get icon
  console.log('\nSelect an icon:');
  console.log('1. Default icon (fa-light fa-default)');
  console.log('2. Box (fa-solid fa-box)');
  console.log('3. User (fa-solid fa-user)');
  console.log('4. Shopping cart (fa-solid fa-shopping-cart)');
  console.log('5. File (fa-solid fa-file)');
  console.log('6. Custom icon');

  const iconChoice = await askQuestion('Select option (1-6): ', '1');
  const iconOptions = [
    'fa-light fa-default',
    'fa-solid fa-box',
    'fa-solid fa-user',
    'fa-solid fa-shopping-cart',
    'fa-solid fa-file',
  ];

  if (iconChoice >= 1 && iconChoice <= 5) {
    data.icon = iconOptions[iconChoice - 1];
  } else if (iconChoice == 6) {
    data.icon = await askQuestion('Enter custom icon (format: fa-solid fa-xyz): ', 'fa-solid fa-star');
  }

  // Show summary
  console.log('\n=== Summary ===');
  console.log(`Module: ${data.moduleName}`);
  console.log(`Entity: ${data.name}`);
  console.log('Properties:');

  // Sort properties by order for display
  const propSummary = data.properties.map((prop, i) => ({
    name: prop,
    widget: data.widgets[i],
    dataType: data.dataTypes[i],
    required: data.required.includes(prop),
    colSpan: data.colSpans[i],
    order: data.orders[i],
    enableSort: data.enableSorts[i],
    enableFilter: data.enableFilters[i],
    enableInlineFilter: data.enableInlineFilters[i],
    inColumn: data.inColumn[i],
  }));

  // Sort by order
  propSummary.sort((a, b) => a.order - b.order);

  propSummary.forEach((prop) => {
    console.log(
      `  - ${prop.name} (Widget: ${prop.widget}, Type: ${prop.dataType}${prop.required ? ', Required' : ''}, ColSpan: ${prop.colSpan}, Order: ${prop.order}, Sort: ${prop.enableSort ? 'Enabled' : 'Disabled'}, Filter: ${prop.enableFilter ? 'Enabled' : 'Disabled'}, Inline Filter: ${prop.enableInlineFilter ? 'Enabled' : 'Disabled'}, In Column: ${prop.inColumn === 'true' ? 'Yes' : 'No'})`,
    );
  });

  console.log(`Icon: ${data.icon}`);

  const confirm = await askQuestion('\nGenerate entity with these settings? (y/n): ', 'y');
  if (confirm.toLowerCase() === 'y') {
    runNxGenerator();
  } else {
    console.log('Operation cancelled');
    rl.close();
  }
}

// Helper function to ask questions and get answers
function askQuestion(question, defaultAnswer) {
  return new Promise((resolve) => {
    const prompt = defaultAnswer ? `${question} [${defaultAnswer}] ` : question;

    rl.question(prompt, (answer) => {
      // If answer is empty and there's a default, use the default
      const result = answer.trim() === '' && defaultAnswer ? defaultAnswer : answer.trim();
      resolve(result);
    });
  });
}

// Helper function to select a widget with filtering capability
async function selectWidget(prompt) {
  console.log(`\n${prompt}`);
  console.log('Available widgets (you can type to filter):');

  // Display widgets by groups
  for (const [groupName, groupWidgets] of Object.entries(widgetGroups)) {
    console.log(`\n${groupName} widgets:`);
    groupWidgets.forEach((widget, index) => {
      const widgetKey = Object.entries(widgetCatalog).find(([key, value]) => value === widget)?.[0] || '';
      console.log(`  ${(index + 1).toString().padStart(2)}: ${widget} (${widgetKey})`);
    });
  }

  // Handling widget selection with filtering
  let selectedWidget = '';
  while (!selectedWidget) {
    const input = await askQuestion('\nEnter widget name or number (or part of name to filter): ');

    // Check if input is a number
    if (!isNaN(input) && input > 0 && input <= Object.values(widgetCatalog).length) {
      const allWidgets = Object.values(widgetCatalog);
      selectedWidget = allWidgets[parseInt(input) - 1];
    }
    // Check if input exactly matches a widget name
    else if (Object.values(widgetCatalog).includes(input)) {
      selectedWidget = input;
    }
    // Check if input matches a widget key
    else if (widgetCatalog[input]) {
      selectedWidget = widgetCatalog[input];
    }
    // Filter widgets by input
    else {
      const filteredWidgets = Object.entries(widgetCatalog).filter(
        ([key, value]) =>
          key.toLowerCase().includes(input.toLowerCase()) || value.toLowerCase().includes(input.toLowerCase()),
      );

      if (filteredWidgets.length === 1) {
        selectedWidget = filteredWidgets[0][1]; // Pick the only match
      } else if (filteredWidgets.length > 1) {
        console.log('\nFiltered widgets:');
        filteredWidgets.forEach(([key, value], index) => {
          console.log(`  ${(index + 1).toString().padStart(2)}: ${value} (${key})`);
        });

        const selection = await askQuestion('Select number or continue typing to filter more: ');
        if (!isNaN(selection) && selection > 0 && selection <= filteredWidgets.length) {
          selectedWidget = filteredWidgets[parseInt(selection) - 1][1];
        }
      } else {
        console.log('No matches found. Try again.');
      }
    }
  }

  return selectedWidget;
}

// Run the NX generator with collected data
function runNxGenerator() {
  // Handle special cases and ensure proper formatting

  // For empty required array, use "_none_"
  const requiredValue = data.required.length === 0 ? '_none_' : data.required.join(',');

  // Ensure single values for colSpans and orders have trailing commas
  let colSpansStr = data.colSpans.join(',');
  if (data.colSpans.length === 1) {
    colSpansStr = colSpansStr + ',';
  }

  let ordersStr = data.orders.join(',');
  if (data.orders.length === 1) {
    ordersStr = ordersStr + ',';
  }

  // Prepare arguments properly
  const command =
    `cd "${projectRoot}" && npx nx g @acorex-platform/generator:create-module-entity` +
    ` --moduleName=${data.moduleName}` +
    ` --name=${data.name}` +
    ` --properties=${data.properties.join(',')}` +
    ` --dataTypes=${data.dataTypes.join(',')}` +
    ` --required=${requiredValue}` +
    ` --colSpans=${colSpansStr}` +
    ` --orders=${ordersStr}` +
    ` --icon="${data.icon}"` +
    ` --enableSorts=${data.enableSorts.join(',')}` +
    ` --enableFilters=${data.enableFilters.join(',')}` +
    ` --enableInlineFilters=${data.enableInlineFilters.join(',')}` +
    ` --inColumn=${data.inColumn.join(',')}` +
    (isDryRun ? ' --dryRun' : '');

  console.log(`\nRunning: ${command}`);

  try {
    // Execute the command as a shell command to ensure proper environment
    const { execSync } = require('child_process');
    const options = {
      stdio: 'inherit',
      shell: true,
    };

    execSync(command, options);
    console.log(`\nGenerator completed successfully`);
  } catch (error) {
    console.error(`\nGenerator failed with error: ${error.message}`);

    // Show more detailed error information
    if (error.stderr) {
      console.error(`Error details: ${error.stderr.toString()}`);
    }
  } finally {
    rl.close();
  }
}

// Start the prompts
runPrompts().catch((err) => {
  console.error('An error occurred:', err);
  rl.close();
});
