#!/usr/bin/env node

/**
 * Custom Angular Template Formatter
 * Enforces specific formatting rules for Angular HTML templates:
 * 1. Blank lines between sibling elements (except first)
 * 2. Property grouping: outputs → two-way → inputs → attributes
 * 3. Multi-line properties when 3+
 * 4. Proper indentation in @if/@for/@switch blocks
 */

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

const PROPERTY_ORDER = {
  'STRUCTURAL_DIRECTIVE': 0,
  'TEMPLATE_REFERENCE': 1,
  'OUTPUT_BINDING': 2,
  'TWO_WAY_BINDING': 3,
  'INPUT_BINDING': 4,
  'ATTRIBUTE_BINDING': 5,
};

// Detect property type
function getPropertyType(attr) {
  if (attr.match(/^\(\w+\)/)) return 'OUTPUT_BINDING'; // (click)
  if (attr.match(/^\[\(\w+\)\]/)) return 'TWO_WAY_BINDING'; // [(ngModel)]
  if (attr.match(/^\[[\w\-.]+\]/)) return 'INPUT_BINDING'; // [property]
  if (attr.match(/^#\w+/)) return 'TEMPLATE_REFERENCE'; // #ref
  if (attr.match(/^@/)) return 'STRUCTURAL_DIRECTIVE'; // @if
  return 'ATTRIBUTE_BINDING'; // class, id, etc.
}

// Sort attributes by property type
function sortAttributes(attrs) {
  return attrs.sort((a, b) => {
    const typeA = getPropertyType(a);
    const typeB = getPropertyType(b);
    return (PROPERTY_ORDER[typeA] || 99) - (PROPERTY_ORDER[typeB] || 99);
  });
}

// Format an element's attributes
function formatAttributes(element) {
  const attrRegex = /(\s+)([\w\-\.\:\@\[\(\#\*]+(?:[\w\-\.\:\@\[\(\#\*\)"'=\s\[\]]*)?)/g;
  
  // Extract all attributes
  const matches = element.match(/\s+[^\s>]+(?:="[^"]*")?/g) || [];
  if (!matches.length) return element;

  const attrs = matches
    .map(m => m.trim())
    .filter(m => m.length > 0);

  // Sort attributes
  const sorted = sortAttributes(attrs);

  // Format based on count
  if (sorted.length <= 2) {
    // Keep on same line if 2 or fewer
    return element.replace(/\s+[\w\-\.\:\@\[\(\#\*][^\s>]*(?:="[^"]*")?/g, '').replace(/>/, ' ' + sorted.join(' ') + '>');
  } else {
    // Put each on new line if 3+
    const indent = '    '; // Assuming 4-space indent
    const tag = element.match(/^<\w+/)[0];
    return tag + '\n' + sorted.map(a => indent + a).join('\n') + '\n>';
  }
}

// Add blank lines between siblings
function addBlankLinesBetweenSiblings(content) {
  // Match closing and opening tags on consecutive lines
  const pattern = /(<\/\w+>)\n(?!$)(<\w+|\s*<\w+|\s*@)/gm;
  return content.replace(pattern, '$1\n\n$2');
}

// Ensure @if/@for/@switch blocks are properly indented
function formatControlFlowBlocks(content) {
  const controlFlowRegex = /@(if|for|switch|case|default)\s*\([^)]*\)\s*\{/g;
  let result = content;

  result = result.replace(controlFlowRegex, (match) => {
    // Ensure content after { is on new line and indented
    return match.replace(/\}\s*$/m, '}\n');
  });

  return result;
}

// Main formatter function
function formatAngularTemplate(content) {
  // First, add blank lines between siblings
  content = addBlankLinesBetweenSiblings(content);

  // Ensure control flow blocks are properly formatted
  content = formatControlFlowBlocks(content);

  return content;
}

// Process a file
function processFile(filePath) {
  try {
    let content = fs.readFileSync(filePath, 'utf-8');
    const original = content;

    content = formatAngularTemplate(content);

    if (content !== original) {
      fs.writeFileSync(filePath, content, 'utf-8');
      console.log(`✓ Formatted: ${filePath}`);
      return true;
    }
  } catch (error) {
    console.error(`✗ Error processing ${filePath}:`, error.message);
  }
  return false;
}

// Main
const args = process.argv.slice(2);
const files = args.length > 0 
  ? args 
  : glob.sync('toju-app/src/app/**/*.html', { cwd: process.cwd() });

let formatted = 0;
files.forEach(file => {
  const fullPath = path.join(process.cwd(), file);
  if (fs.existsSync(fullPath)) {
    if (processFile(fullPath)) {
      formatted++;
    }
  }
});

console.log(`\nTotal files formatted: ${formatted}`);
process.exit(formatted > 0 ? 0 : 0);
