// See flow-to-typescript-codemod.sh for documentation

type FileInfo = { path: string; source: string }

export const parser = 'flow'

function logger(fileInfo: FileInfo, msg, node) {
  const lineInfo = node && node.value.loc ? ` line ${node.value.loc.start.line}` : ''
  console.warn(`warning: (${fileInfo.path}${lineInfo}) ${msg}`)
}

export default function flowToTypeScript(fileInfo: FileInfo, api: any, options: any) {
  const j = api.jscodeshift
  const ast = j(fileInfo.source)

  const logWarning = (msg: string, node: any) => logger(fileInfo, msg, node)

  const transforms = [
    function updateFunctionTypeParams() {
      ast.find(j.FunctionTypeParam, { name: null }).forEach((p: any) => {
        p.value.name = j.identifier('arg')
      })
    },
    function fixDuplicateImports() {
      const fileToImportCount = {}
      const fileToSpecifiers = {}

      ast.find(j.ImportDeclaration).forEach((p: any) => {
        const file = p.value.source.value
        if (!(file in fileToSpecifiers)) {
          fileToSpecifiers[file] = []
        }
        fileToSpecifiers[file] = [...fileToSpecifiers[file], ...p.value.specifiers]

        if (!(file in fileToImportCount)) {
          fileToImportCount[file] = 0
        } else {
          p.prune()
        }
        fileToImportCount[file] += 1
      })

      Object.keys(fileToImportCount).map(file => {
        if (fileToImportCount[file] > 1) {
          ast.find(j.ImportDeclaration, { source: { value: file } }).forEach((p: any) => {
            p.value.specifiers = fileToSpecifiers[file]
          })
        }
      })
    },
    function removeExactTypes() {
      ast.find(j.ObjectTypeAnnotation, { exact: true }).forEach((p: any) => {
        p.value.exact = false
        p.value.inexact = true
      })
    },
  ]

  transforms.forEach(t => t())

  return ast.toSource({
    arrowParensAlways: true,
    flowObjectCommas: true,
    quote: 'single',
  })
}