import { isArray } from '../helpers.mts';
import type { ParseNode } from '../parser/ParseNode.mts';
import { TopLevelLexicallyScopedDeclarations, DeclarationPart } from './all.mts';

export function LexicallyScopedDeclarations(node: ParseNode | readonly ParseNode[]): (ParseNode.Declaration | ParseNode.ExportDeclaration)[] {
  if (isArray(node)) {
    const declarations = [];
    for (const item of node) {
      declarations.push(...LexicallyScopedDeclarations(item));
    }
    return declarations;
  }
  switch (node.type) {
    case 'LabelledStatement':
      return LexicallyScopedDeclarations(node.LabelledItem);
    case 'Script':
      if (node.ScriptBody) {
        return LexicallyScopedDeclarations(node.ScriptBody);
      }
      return [];
    case 'ScriptBody':
      return TopLevelLexicallyScopedDeclarations(node.StatementList);
    case 'Module':
      if (node.ModuleBody) {
        return LexicallyScopedDeclarations(node.ModuleBody);
      }
      return [];
    case 'ModuleBody':
      return LexicallyScopedDeclarations(node.ModuleItemList);
    case 'FunctionBody':
    case 'GeneratorBody':
    case 'AsyncBody':
    case 'AsyncGeneratorBody':
      return TopLevelLexicallyScopedDeclarations(node.FunctionStatementList);
    case 'ClassStaticBlockBody':
      return TopLevelLexicallyScopedDeclarations(node.ClassStaticBlockStatementList);
    case 'ImportDeclaration':
      return [];
    case 'ClassDeclaration':
    case 'LexicalDeclaration':
    case 'FunctionDeclaration':
    case 'GeneratorDeclaration':
    case 'AsyncFunctionDeclaration':
    case 'AsyncGeneratorDeclaration':
      return [DeclarationPart(node)];
    case 'CaseBlock': {
      const names = [];
      if (node.CaseClauses_a) {
        names.push(...LexicallyScopedDeclarations(node.CaseClauses_a));
      }
      if (node.DefaultClause) {
        names.push(...LexicallyScopedDeclarations(node.DefaultClause));
      }
      if (node.CaseClauses_b) {
        names.push(...LexicallyScopedDeclarations(node.CaseClauses_b));
      }
      return names;
    }
    case 'CaseClause':
    case 'DefaultClause':
      if (node.StatementList) {
        return LexicallyScopedDeclarations(node.StatementList);
      }
      return [];
    case 'ExportDeclaration':
      if (node.Declaration) {
        return [DeclarationPart(node.Declaration)];
      }
      if (node.HoistableDeclaration) {
        return [DeclarationPart(node.HoistableDeclaration)];
      }
      if (node.ClassDeclaration) {
        return [node.ClassDeclaration];
      }
      if (node.AssignmentExpression) {
        return [node];
      }
      return [];
    default:
      return [];
  }
}
