import fs from 'fs';
import ts from 'typescript';
export const TABLE_BO_MAPPING = {
  'users':'User',
  'businesses':'BusinessListing',
  'commercials':'CommercialPropertyListing'
}
function generateInterfaceDefinitions(inputFile: string, outputFile: string): void {
  const sourceFile = ts.createSourceFile(
    inputFile,
    fs.readFileSync(inputFile, 'utf8'),
    ts.ScriptTarget.Latest,
    true
  );

  let interfaceDefinitions = '';

  ts.forEachChild(sourceFile, (node) => {
    if (ts.isVariableStatement(node)) {
      const variableDeclaration = node.declarationList.declarations[0];
      if (variableDeclaration.initializer && ts.isCallExpression(variableDeclaration.initializer)) {
        const initializer = variableDeclaration.initializer;
        if (initializer.expression.getText(sourceFile) === 'pgTable') {
          const tableName = initializer.arguments[0].getText(sourceFile).slice(1, -1);  // Entfernen von zusätzlichen Anführungszeichen
          const tableDefinition = initializer.arguments[1];

          const interfaceName = TABLE_BO_MAPPING[tableName] ? TABLE_BO_MAPPING[tableName] : tableName.charAt(0).toUpperCase() + tableName.slice(1);
          let interfaceDefinition = `export interface ${interfaceName} {\n`;

          ts.forEachChild(tableDefinition, (propertyNode) => {
            if (ts.isPropertyAssignment(propertyNode)) {
              const propertyName = propertyNode.name.getText(sourceFile);
              const propertyDefinition = propertyNode.initializer;

              if (ts.isCallExpression(propertyDefinition)) {
                const propertyType = getPropertyType(propertyDefinition, sourceFile);
                const isOptional = !hasNonOptionalModifier(propertyDefinition.expression);
                interfaceDefinition += `  ${propertyName}${isOptional ? '?' : ''}: ${propertyType};\n`;
              }
            }
          });

          interfaceDefinition += '}\n\n';
          interfaceDefinitions += interfaceDefinition;
        }
      }
    }
  });

  fs.writeFileSync(outputFile, interfaceDefinitions);
  console.log(`Interface definitions generated successfully. Output file: ${outputFile}`);
}

function getPropertyType(propertyDefinition: ts.CallExpression, sourceFile: ts.SourceFile): string {
  const typeFunction = getTypeFunctionName(propertyDefinition.expression, sourceFile);

  let propertyType = '';

  switch (typeFunction) {
    case 'varchar':
    case 'char':
    case 'text':
    case 'uuid':
      propertyType = 'string';
      break;
    case 'integer':
    case 'numeric':
    case 'real':
    case 'doublePrecision':
      propertyType = 'number';
      break;
    case 'boolean':
      propertyType = 'boolean';
      break;
    case 'timestamp':
      propertyType = 'Date';
      break;
    default:
      propertyType = 'any';
  }

  const isArray = hasArrayModifier(propertyDefinition.expression);
  return isArray ? `${propertyType}[]` : propertyType;
}

function getTypeFunctionName(expression: ts.Expression, sourceFile: ts.SourceFile): string {
  // Prüfen, ob die aktuelle Expression ein Identifier ist (SyntaxKind.Identifier hat den Wert 80)
  if (expression.kind === ts.SyntaxKind.Identifier) {
    return expression.getText(sourceFile);
  }
  
  // Wenn die Expression eine CallExpression oder eine PropertyAccessExpression ist,
  // gehe zur nächsten Expression-Ebene
  if (ts.isCallExpression(expression) || ts.isPropertyAccessExpression(expression)) {
    return getTypeFunctionName(expression.expression, sourceFile);
  }
  
  // Falls ein nicht unterstützter Expression-Typ vorliegt, gibt 'unknown' zurück
  return 'unknown';
}

function hasArrayModifier(expression: ts.Expression): boolean {
  // Prüfe, ob die aktuelle Expression eine CallExpression ist und der Funktionsname 'array' ist
  if (ts.isPropertyAccessExpression(expression) && expression.name.getText() === 'array') {
    return true;
  }

  // Wenn die Expression eine weitere CallExpression oder PropertyAccessExpression ist,
  // prüfe rekursiv die nächste Ebene
  if (ts.isCallExpression(expression) || ts.isPropertyAccessExpression(expression)) {
    return hasArrayModifier(expression.expression);
  }

  // Wenn keine weitere Ebene oder kein Array-Modifier gefunden wurde, gib false zurück
  return false;
}

function hasNonOptionalModifier(expression: ts.Expression): boolean {
  // Prüfe, ob die aktuelle Expression eine CallExpression ist und der Funktionsname 'notNull' ist
  if (ts.isPropertyAccessExpression(expression) && (expression.name.getText() === 'notNull' || expression.name.getText() === 'primaryKey')) {
    return true;
  }

  // Wenn die Expression eine weitere CallExpression oder PropertyAccessExpression ist,
  // prüfe rekursiv die nächste Ebene
  if (ts.isCallExpression(expression) || ts.isPropertyAccessExpression(expression)) {
    return hasNonOptionalModifier(expression.expression);
  }

  // Wenn keine weitere Ebene oder kein NotNull-Modifier gefunden wurde, gib false zurück
  return false;
}

// Hauptprogramm
const inputFile = process.argv[2]|| './src/drizzle/schema.ts';
const outputFile = process.argv[3] || './model.ts';

if (!inputFile) {
  console.error('Please provide an input file.');
  process.exit(1);
}

generateInterfaceDefinitions(inputFile, outputFile);
