/**
 * jscodeshift transform: client-side next-auth v4 -> v5 migration.
 *
 * Converts:
 *   import { getServerSession } from 'next-auth/next';
 *   const session = await getServerSession();
 *
 * Into:
 *   import { auth } from 'auth';
 *   const session = await auth();
 *
 * Arguments passed to `getServerSession(authOptions, ...)` are dropped,
 * since `auth()` needs none when using the root `src/auth.ts` config.
 */

const AUTH_IMPORT_SOURCES = ['next-auth/next', 'next-auth'];

function transform(fileInfo, api) {
  const j = api.jscodeshift;
  const root = j(fileInfo.source);
  let changed = false;

  AUTH_IMPORT_SOURCES.forEach((sourceValue) => {
    const imports = root.find(j.ImportDeclaration, {
      source: { value: sourceValue }
    });

    imports.forEach((pathNode) => {
      const specifiers = pathNode.node.specifiers || [];
      const getServerSessionSpec = specifiers.find(
        (s) =>
          s.type === 'ImportSpecifier' &&
          s.imported &&
          s.imported.name === 'getServerSession'
      );

      if (!getServerSessionSpec) {
        return;
      }

      const localName = getServerSessionSpec.local
        ? getServerSessionSpec.local.name
        : 'getServerSession';

      const otherSpecs = specifiers.filter((s) => s !== getServerSessionSpec);

      if (otherSpecs.length === 0) {
        pathNode.node.specifiers = [
          j.importSpecifier(j.identifier('auth'))
        ];
        pathNode.node.source = j.literal('auth');
      } else {
        pathNode.node.specifiers = otherSpecs;
        const authImport = j.importDeclaration(
          [j.importSpecifier(j.identifier('auth'))],
          j.literal('auth')
        );
        pathNode.insertAfter(authImport);
      }

      root
        .find(j.CallExpression, { callee: { name: localName } })
        .forEach((callPath) => {
          callPath.node.callee = j.identifier('auth');
          callPath.node.arguments = [];
        });

      changed = true;
    });
  });

  AUTH_IMPORT_SOURCES.forEach((sourceValue) => {
    root
      .find(j.ImportDeclaration, { source: { value: sourceValue } })
      .forEach((pathNode) => {
        if (!pathNode.node.specifiers || pathNode.node.specifiers.length === 0) {
          j(pathNode).remove();
          changed = true;
        }
      });
  });

  return changed ? root.toSource({ quote: 'single' }) : null;
}

module.exports = transform;
