import * as ts from 'typescript';
import { TypeScriptProject } from './createTypeScriptProject';

function shouldAliasSymbol(symbol: ts.Symbol) {
  const declaration = symbol.declarations?.[0];
  if (!declaration) {
    return false;
  }

  /**
   * - `export { XXX }`
   * - `export { XXX } from './modules'`
   */
  if (ts.isExportSpecifier(declaration)) {
    return true;
  }

  /**
   * - `export default XXX`
   */
  if (ts.isExportAssignment(declaration)) {
    /**
     * Return `true` only for `export default XXX`
     * Not for `export default React.memo(XXX)` for example.
     */
    return declaration.expression.kind === ts.SyntaxKind.Identifier;
  }

  return false;
}

/**
 * Goes to the root symbol of ExportSpecifier
 * That corresponds to one of the following patterns
 * - `export { XXX }`
 * - `export { XXX } from './modules'`
 * - `export default XXX`
 *
 * Do not go to the root definition for TypeAlias (ie: `export type XXX = YYY`)
 * Because we usually want to keep the description and tags of the aliased symbol.
 */
export default function resolveExportSpecifier(symbol: ts.Symbol, project: TypeScriptProject) {
  let resolvedSymbol = symbol;

  while (shouldAliasSymbol(resolvedSymbol)) {
    let newResolvedSymbol;
    try {
      newResolvedSymbol = project.checker.getImmediateAliasedSymbol(resolvedSymbol);
    } catch (err) {
      newResolvedSymbol = null;
    }

    if (!newResolvedSymbol) {
      throw new Error(`Impossible to resolve export specifier for symbol "${symbol.escapedName}"`);
    }

    resolvedSymbol = newResolvedSymbol;
  }

  return resolvedSymbol;
}
