#!/usr/bin/env python3
import pathlib
import re
import sys
from datetime import date

import packaging.version

CHANGELOG_HEADER = "Change Log\n==========\n\nPRAW follows `semantic versioning <https://semver.org/>`_.\n\n"
UNRELEASED_HEADER = "Unreleased\n----------\n\n"


def add_unreleased_to_changelog():
    content = pathlib.Path("CHANGES.rst").read_text()

    if not content.startswith(CHANGELOG_HEADER):
        sys.stderr.write("Unexpected CHANGES.rst header\n")
        return False
    new_header = f"{CHANGELOG_HEADER}{UNRELEASED_HEADER}"
    if content.startswith(new_header):
        sys.stderr.write("CHANGES.rst already contains Unreleased header\n")
        return False

    pathlib.Path("CHANGES.rst").write_text(f"{new_header}{content[len(CHANGELOG_HEADER) :]}")
    return True


def handle_unreleased():
    return add_unreleased_to_changelog() and increment_development_version()


def handle_version(version):
    version = valid_version(version)
    if not version:
        return False
    return update_changelog(version) and update_package(version)


def increment_development_version():
    version = re.search(r'__version__ = "([^"]+)"', pathlib.Path("praw/const.py").read_text()).group(1)

    parsed_version = valid_version(version)
    if not parsed_version:
        return False

    if parsed_version.is_devrelease:
        pre = "".join(str(x) for x in parsed_version.pre) if parsed_version.pre else ""
        new_version = f"{parsed_version.base_version}{pre}.dev{parsed_version.dev + 1}"
    elif parsed_version.is_prerelease:
        new_version = f"{parsed_version}.dev0"
    else:
        assert parsed_version.base_version == version
        new_version = f"{parsed_version.major}.{parsed_version.minor}.{parsed_version.micro + 1}.dev0"

    assert valid_version(new_version)
    return update_package(new_version)


def main():
    if len(sys.argv) != 2:
        sys.stderr.write(f"Usage: {sys.argv[0]} VERSION\n")
        return 1
    if sys.argv[1] == "Unreleased":
        return not handle_unreleased()
    return not handle_version(sys.argv[1])


def update_changelog(version):
    content = pathlib.Path("CHANGES.rst").read_text()

    expected_header = f"{CHANGELOG_HEADER}{UNRELEASED_HEADER}"
    if not content.startswith(expected_header):
        sys.stderr.write("CHANGES.rst does not contain Unreleased header.\n")
        return False

    date_string = date.today().strftime("%Y/%m/%d")
    version_line = f"{version} ({date_string})\n"
    version_header = f"{version_line}{'-' * len(version_line[:-1])}\n\n"

    pathlib.Path("CHANGES.rst").write_text(f"{CHANGELOG_HEADER}{version_header}{content[len(expected_header) :]}")
    return True


def update_package(version):
    content = pathlib.Path("praw/const.py").read_text()

    updated = re.sub(r'__version__ = "([^"]+)"', f'__version__ = "{version}"', content)
    if content == updated:
        sys.stderr.write("Package version string not changed\n")
        return False

    pathlib.Path("praw/const.py").write_text(updated)

    print(version)
    return True


def valid_version(version):
    parsed_version = packaging.version.parse(version)
    if parsed_version.local or parsed_version.is_postrelease or parsed_version.epoch:
        sys.stderr.write("epoch, local postrelease version parts are not supported")
        return False
    return parsed_version


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