#!/usr/bin/env python3
# Copyright 2022 The Emscripten Authors.  All rights reserved.
# Emscripten is available under two separate licenses, the MIT license and the
# University of Illinois/NCSA Open Source License.  Both these licenses can be
# found in the LICENSE file.

import argparse
import os
import subprocess
import sys
from datetime import datetime

script_dir = os.path.dirname(os.path.abspath(__file__))
root_dir = os.path.dirname(os.path.dirname(script_dir))

sys.path.insert(0, root_dir)
from tools import utils

REPO = 'emscripten-core/emscripten'


def get_repo_url():
  # Pick correct URL for pushing to REPO (emscripten-core/emscripten).
  remotes = subprocess.check_output(['git', 'remote', '-v'], text=True, cwd=root_dir)
  for line in remotes.splitlines():
    _name, url, url_type = line.split()
    if REPO in url and url_type == '(push)':
      return url

  # If we can't find a URL to push to then just abort
  raise Exception(f'Unable to determine remote URL for {REPO}')


def update_version_txt(release_version, new_version):
  version_file = os.path.join(root_dir, 'emscripten-version.txt')
  old_content = utils.read_file(version_file)
  utils.write_file(version_file, old_content.replace(release_version, new_version))


def update_changelog(release_version, new_version):
  changelog_file = os.path.join(root_dir, 'ChangeLog.md')
  changelog = utils.read_file(changelog_file)
  marker = f'{release_version} (in development)'
  pos = changelog.find(marker)
  assert pos != -1
  pos += len(marker) + 1
  # Skip the next line which should just be hyphens
  assert changelog[pos] == '-'
  pos = changelog.find('\n', pos)
  assert pos != -1

  # Add new entry
  today = datetime.now().strftime('%m/%d/%y')
  new_entry = f'{release_version} - {today}'
  new_entry = '\n\n' + new_entry + '\n' + ('-' * len(new_entry))
  changelog = changelog[:pos] + new_entry + changelog[pos:]

  # Update the "in development" entry
  changelog = changelog.replace(f'{release_version} (in development)', f'{new_version} (in development)')

  utils.write_file(changelog_file, changelog)


def create_release_pr(release_version, dry_run):
  branch_name = 'version_' + release_version

  print(f'Creating new branch {branch_name}')
  subprocess.check_call(['git', 'checkout', '-b', branch_name], cwd=root_dir)

  # Create auto-generated changes to the new git branch
  subprocess.check_call(['git', 'add', '-u', '.'], cwd=root_dir)
  subprocess.check_call(['git', 'commit', '-m', f'Mark {release_version} as released'], cwd=root_dir)
  print('New release created in branch: `%s`' % branch_name)

  if not dry_run:
    # Push the new branch to emscripten repo and create PR
    repo_url = get_repo_url()
    subprocess.check_call(['git', 'push', repo_url, branch_name], cwd=root_dir)
    subprocess.check_call(['gh', 'pr', 'create', '--fill', '--reviewer', 'emscripten-core/release-reviewers', '--head', branch_name, '-R', REPO], cwd=root_dir)


def create_draft_release(version, base_commit):
  print(f'Creating draft release for {version}...', file=sys.stderr)

  # Call gen_release_notes.py
  gen_script = os.path.join(script_dir, 'gen_release_notes.py')
  notes = subprocess.check_output([sys.executable, gen_script, version], text=True)

  # Save notes to out/release-notes-{version}.md
  out_dir = os.path.join(root_dir, 'out')
  os.makedirs(out_dir, exist_ok=True)
  notes_file = os.path.join(out_dir, f'release-notes-{version}.md')
  with open(notes_file, 'w', encoding='utf-8') as f:
    f.write(notes)

  # Create the draft release
  cmd = [
      'gh', 'release', 'create', version,
      '--draft',
      '--title', version,
      '--notes-file', notes_file,
      '-R', REPO,
  ]
  if base_commit:
    cmd.extend(['--target', base_commit])
  subprocess.run(cmd, check=True)
  print(f'Draft release created successfully! Notes saved to {notes_file}', file=sys.stderr)
  return 0


def main():
  parser = argparse.ArgumentParser(description=__doc__)
  parser.add_argument('-n', '--dry-run', action='store_true', help='Dry run (do not push branch/tag/release)')
  parser.add_argument('--release-commit', help='Base commit/SHA for the release')
  args = parser.parse_args()

  if subprocess.check_output(['git', 'status', '-uno', '--porcelain'], cwd=root_dir).strip():
    print('tree is not clean')
    return 1

  utils.set_version_globals()

  release_version = [utils.EMSCRIPTEN_VERSION_MAJOR, utils.EMSCRIPTEN_VERSION_MINOR,
                     utils.EMSCRIPTEN_VERSION_TINY]
  new_dev_version = list(release_version)
  new_dev_version[2] += 1

  release_version = '.'.join(str(v) for v in release_version)
  new_dev_version = '.'.join(str(v) for v in new_dev_version)

  update_version_txt(release_version, new_dev_version)
  update_changelog(release_version, new_dev_version)

  print('Creating new release: %s' % release_version)

  create_release_pr(release_version, args.dry_run)

  if not args.dry_run:
    create_draft_release(release_version, args.release_commit)

  return 0


if __name__ == '__main__':
  sys.exit(main())
