/**
 * Output formatter for hana-cli MCP server
 * Improves readability of command outputs
 */

interface TableData {
  headers: string[];
  rows: string[][];
}

/**
 * Parse ASCII table output from hana-cli
 */
function parseAsciiTable(output: string): TableData | null {
  const lines = output.split('\n').filter(line => line.trim());

  // Find header row (contains │ separators)
  const headerIndex = lines.findIndex(line => line.includes('│') && !line.startsWith('╭') && !line.startsWith('├'));
  if (headerIndex === -1) return null;

  const headerLine = lines[headerIndex];
  // Split by │ and drop the leading/trailing empty segments from outer borders
  const headers = headerLine
    .split('│')
    .slice(1, -1)
    .map(h => h.trim());

  if (headers.length === 0) return null;

  // Parse data rows
  const rows: string[][] = [];
  for (let i = headerIndex + 1; i < lines.length; i++) {
    const line = lines[i];
    if (line.startsWith('├') || line.startsWith('╰')) continue;
    if (!line.includes('│')) continue;

    const cells = line
      .split('│')
      .slice(1, -1)
      .map(c => c.trim());

    if (cells.length === headers.length) {
      rows.push(cells);
    }
  }

  return { headers, rows };
}

/**
 * Shorten schema names (UUIDs) to last 6 characters
 */
function shortenSchemaName(schema: string): string {
  if (schema.length > 32 && schema.match(/^[A-F0-9]+$/)) {
    return '...' + schema.slice(-6);
  }
  return schema;
}

/**
 * Group tables by prefix
 */
function groupTables(tables: string[]): Map<string, string[]> {
  const groups = new Map<string, string[]>();
  
  for (const table of tables) {
    const prefix = table.split('_')[0];
    if (!groups.has(prefix)) {
      groups.set(prefix, []);
    }
    groups.get(prefix)!.push(table);
  }
  
  return groups;
}

/**
 * Format table data as markdown
 */
function formatAsMarkdown(data: TableData): string {
  const { headers, rows } = data;
  
  // Calculate column widths
  const widths = headers.map((h, i) => {
    // Handle empty rows case: Math.max() with empty array returns -Infinity
    const cellLengths = rows.map(r => (r[i] || '').length);
    const maxCellWidth = cellLengths.length > 0 ? Math.max(...cellLengths) : 0;
    return Math.max(h.length, maxCellWidth);
  });

  // Build markdown table
  let output = '\n| ' + headers.map((h, i) => h.padEnd(widths[i])).join(' | ') + ' |\n';
  output += '| ' + widths.map(w => '-'.repeat(w)).join(' | ') + ' |\n';
  
  for (const row of rows) {
    output += '| ' + row.map((cell, i) => (cell || '').padEnd(widths[i] || 0)).join(' | ') + ' |\n';
  }
  
  return output;
}

/**
 * Format tables command output
 */
function formatTablesOutput(output: string): string {
  const table = parseAsciiTable(output);
  if (!table) return output;

  const { headers, rows } = table;
  
  // Find schema and table name columns
  const schemaIdx = headers.findIndex(h => h.includes('SCHEMA'));
  const tableIdx = headers.findIndex(h => h.includes('TABLE_NAME'));
  
  if (schemaIdx === -1 || tableIdx === -1) return output;

  // Process rows
  const processedRows = rows.map(row => {
    const newRow = [...row];
    if (schemaIdx < newRow.length) {
      newRow[schemaIdx] = shortenSchemaName(newRow[schemaIdx]);
    }
    return newRow;
  });

  // Group tables
  const tableNames = processedRows.map(r => r[tableIdx]);
  const groups = groupTables(tableNames);

  // Build formatted output
  let result = '\n## Database Tables\n\n';
  result += `**Total Tables:** ${rows.length}\n\n`;

  // Show table groups
  result += '### Table Groups:\n';
  for (const [prefix, tables] of Array.from(groups.entries()).sort()) {
    result += `- **${prefix}**: ${tables.length} tables\n`;
  }
  result += '\n';

  // Show formatted table
  result += '### Table Details:\n';
  result += formatAsMarkdown({ headers, rows: processedRows });
  
  return result;
}

/**
 * Format schemas command output
 */
function formatSchemasOutput(output: string): string {
  const table = parseAsciiTable(output);
  if (!table) return output;

  const { headers, rows } = table;
  
  // Shorten schema names
  const processedRows = rows.map(row => {
    return row.map((cell, idx) => {
      if (headers[idx]?.includes('SCHEMA')) {
        return shortenSchemaName(cell);
      }
      return cell;
    });
  });

  let result = '\n## Database Schemas\n\n';
  result += `**Total Schemas:** ${rows.length}\n\n`;
  result += formatAsMarkdown({ headers, rows: processedRows });
  
  return result;
}

/**
 * Format views command output
 */
function formatViewsOutput(output: string): string {
  const table = parseAsciiTable(output);
  if (!table) return output;

  const { headers, rows } = table;
  const schemaIdx = headers.findIndex(h => h.includes('SCHEMA'));
  
  const processedRows = rows.map(row => {
    const newRow = [...row];
    if (schemaIdx >= 0 && schemaIdx < newRow.length) {
      newRow[schemaIdx] = shortenSchemaName(newRow[schemaIdx]);
    }
    return newRow;
  });

  let result = '\n## Database Views\n\n';
  result += `**Total Views:** ${rows.length}\n\n`;
  result += formatAsMarkdown({ headers, rows: processedRows });
  
  return result;
}

/**
 * Format procedures command output
 */
function formatProceduresOutput(output: string): string {
  const table = parseAsciiTable(output);
  if (!table) return output;

  const { headers, rows } = table;
  const schemaIdx = headers.findIndex(h => h.includes('SCHEMA'));
  
  const processedRows = rows.map(row => {
    const newRow = [...row];
    if (schemaIdx >= 0 && schemaIdx < newRow.length) {
      newRow[schemaIdx] = shortenSchemaName(newRow[schemaIdx]);
    }
    return newRow;
  });

  let result = '\n## Stored Procedures\n\n';
  result += `**Total Procedures:** ${rows.length}\n\n`;
  result += formatAsMarkdown({ headers, rows: processedRows });
  
  return result;
}

/**
 * Format functions command output
 */
function formatFunctionsOutput(output: string): string {
  const table = parseAsciiTable(output);
  if (!table) return output;

  const { headers, rows } = table;
  const schemaIdx = headers.findIndex(h => h.includes('SCHEMA'));
  
  const processedRows = rows.map(row => {
    const newRow = [...row];
    if (schemaIdx >= 0 && schemaIdx < newRow.length) {
      newRow[schemaIdx] = shortenSchemaName(newRow[schemaIdx]);
    }
    return newRow;
  });

  let result = '\n## Database Functions\n\n';
  result += `**Total Functions:** ${rows.length}\n\n`;
  result += formatAsMarkdown({ headers, rows: processedRows });
  
  return result;
}

/**
 * Format system info output
 */
function formatSystemInfoOutput(output: string): string {
  const table = parseAsciiTable(output);
  if (!table) return output;

  const { headers, rows } = table;
  
  let result = '\n## System Information\n\n';
  
  // Convert to key-value format for better readability
  for (let i = 0; i < headers.length; i++) {
    result += `**${headers[i]}:** ${rows[0]?.[i] || 'N/A'}\n`;
  }
  
  return result;
}

/**
 * Format containers output
 */
function formatContainersOutput(output: string): string {
  const table = parseAsciiTable(output);
  if (!table) return output;

  const { headers, rows } = table;
  
  let result = '\n## HDI Containers\n\n';
  result += `**Total Containers:** ${rows.length}\n\n`;
  result += formatAsMarkdown({ headers, rows });
  
  return result;
}

const COMMAND_FORMATTERS: Record<string, (output: string) => string> = {
  tables: formatTablesOutput,
  schemas: formatSchemasOutput,
  views: formatViewsOutput,
  procedures: formatProceduresOutput,
  functions: formatFunctionsOutput,
  systemInfo: formatSystemInfoOutput,
  sysInfo: formatSystemInfoOutput,
  containers: formatContainersOutput,
};

/**
 * Main formatter function
 */
export function formatOutput(command: string, output: string): string {
  const cleanOutput = output.replace(/Using Connection Configuration.*\n\n?/, '');

  const formatter = COMMAND_FORMATTERS[command];
  if (formatter) {
    return formatter(cleanOutput);
  }

  // For other commands, try generic table formatting
  const table = parseAsciiTable(cleanOutput);
  if (table && table.rows.length > 0) {
    let result = '\n## Command Output\n\n';
    result += `**Total Rows:** ${table.rows.length}\n\n`;
    result += formatAsMarkdown(table);
    return result;
  }

  // Return original output if no formatting applied
  return output;
}