# Copyright 2021 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import argparse
import collections
import json
import os
import re
import sys

_CWD = os.getcwd()
_HERE_DIR = os.path.dirname(__file__)
_SRC_DIR = os.path.normpath(os.path.join(_HERE_DIR, '..', '..'))

sys.path.append(os.path.join(_SRC_DIR, 'third_party', 'node'))
import node
import node_modules


def _write_tsconfig_json(gen_dir, tsconfig):
  if not os.path.exists(gen_dir):
    os.makedirs(gen_dir)

  with open(os.path.join(gen_dir, 'tsconfig.json'), 'w') as generated_tsconfig:
    json.dump(tsconfig, generated_tsconfig, indent=2)
  return


def main(argv):
  parser = argparse.ArgumentParser()
  parser.add_argument('--deps', nargs='*')
  parser.add_argument('--gen_dir', required=True)
  parser.add_argument('--path_mappings', nargs='*')
  parser.add_argument('--root_dir', required=True)
  parser.add_argument('--out_dir', required=True)
  parser.add_argument('--tsconfig_base')
  parser.add_argument('--in_files', nargs='*')
  parser.add_argument('--definitions', nargs='*')
  parser.add_argument('--composite', action='store_true')
  args = parser.parse_args(argv)

  root_dir = os.path.relpath(args.root_dir, args.gen_dir)
  out_dir = os.path.relpath(args.out_dir, args.gen_dir)
  TSCONFIG_BASE_PATH = os.path.join(_HERE_DIR, 'tsconfig_base.json')

  tsconfig = collections.OrderedDict()

  tsconfig['extends'] = args.tsconfig_base \
      if args.tsconfig_base is not None \
      else os.path.relpath(TSCONFIG_BASE_PATH, args.gen_dir)

  tsconfig['compilerOptions'] = collections.OrderedDict()
  tsconfig['compilerOptions']['rootDir'] = root_dir
  tsconfig['compilerOptions']['outDir'] = out_dir

  if args.composite:
    tsbuildinfo_name = 'tsconfig.tsbuildinfo'
    tsconfig['compilerOptions']['composite'] = True
    tsconfig['compilerOptions']['declaration'] = True
    tsconfig['compilerOptions']['tsBuildInfoFile'] = tsbuildinfo_name

  tsconfig['files'] = []
  if args.in_files is not None:
    # Source .ts files are always resolved as being relative to |root_dir|.
    tsconfig['files'].extend([os.path.join(root_dir, f) for f in args.in_files])

  if args.definitions is not None:
    tsconfig['files'].extend(args.definitions)

  # Handle custom path mappings, for example chrome://resources/ URLs.
  if args.path_mappings is not None:
    path_mappings = collections.defaultdict(list)
    for m in args.path_mappings:
      mapping = m.split('|')
      path_mappings[mapping[0]].append(os.path.join('./', mapping[1]))
    tsconfig['compilerOptions']['paths'] = path_mappings

  if args.deps is not None:
    tsconfig['references'] = [{'path': dep} for dep in args.deps]

  _write_tsconfig_json(args.gen_dir, tsconfig)

  # Delete any obsolete .ts files (from previous builds) corresponding to .js
  # |in_files| in the |root_dir| folder, as they would cause the following error
  # to be thrown:
  #
  # "error TS5056: Cannot write file '...' because it would be overwritten by
  # multiple input files."
  #
  # This can happen when a ts_library() is migrating JS to TS one file at a time
  # and a bot is switched from building a later CL to building an earlier CL.
  if args.in_files is not None:
    for f in args.in_files:
      [pathname, extension] = os.path.splitext(f)
      if extension == '.js':
        to_check = os.path.join(args.root_dir, pathname + '.ts')
        if os.path.exists(to_check):
          os.remove(to_check)

  node.RunNode([
      node_modules.PathToTypescript(), '--project',
      os.path.join(args.gen_dir, 'tsconfig.json')
  ])

  if args.composite:
    # `.tsbuildinfo` is generated by TypeScript for incremenetal compilation
    # freshness checks. Since GN already decides which ts_library() targets are
    # dirty, `.tsbuildinfo` is not needed for our purposes and is deleted.
    #
    # Moreover `.tsbuildinfo` can cause flakily failing builds since the TS
    # compiler checks the `.tsbuildinfo` file and sees that none of the source
    # files are changed and does not regenerate any output, without checking
    # whether output files have been modified/deleted, which can lead to bad
    # builds (missing files or picking up obsolete generated files).
    os.remove(os.path.join(args.gen_dir, tsbuildinfo_name))

  if args.in_files is not None:
    with open(os.path.join(args.gen_dir, 'tsconfig.manifest'), 'w') \
        as manifest_file:
      manifest_data = {}
      manifest_data['base_dir'] = args.out_dir
      manifest_data['files'] = \
          [re.sub(r'\.ts$', '.js', f) for f in args.in_files]
      json.dump(manifest_data, manifest_file)


if __name__ == '__main__':
  main(sys.argv[1:])
