# pylint: disable=line-too-long
# pylint: disable=invalid-name
"""
Tools for publishing
"""

import argparse
import datetime
import logging
import re
import subprocess

from tools.bump import bump
from tools.process import run_shell_command, run_shell_command_with_output


LOGGER = logging.getLogger(__name__)


def log_changelog_extract():
    r"""
    Equivalent to awk command
        @awk '/^## v[0-9]+\.[0-9]+\.[0-9]+ \([0-9]{4}-[0-9]{2}-[0-9]{2}\)/ {count++} count<=1' CHANGELOG.md
    """

    with open("CHANGELOG.md", "r", encoding="utf-8") as f:
        lines = f.readlines()

    count = 0
    log_message = ""
    for line in lines:
        if re.match(r"^## v[0-9]+\.[0-9]+\.[0-9]+ \([0-9]{4}-[0-9]{2}-[0-9]{2}\)", line):
            count += 1
            if count > 1:
                break
        log_message += line.strip() + "\n"
    LOGGER.info(log_message)


def publish(part: str = None, version: str = None, dry_run=False):
    """
    Args:
        part: The semver part of the version to be bumped
        version: The version to be used. If set, part is ignored. Use 'today' to use CalVer

    Important:
        This assumes you have made sure this is clean, pre-commit has checked all files etc.
    """
    if part is not None and version is not None:
        raise ValueError("Only one of part or version can be set")
    part = part or "patch"
    dry_run = "" if not dry_run else " --dry-run"
    if part == "today":
        # use CalVer
        part = None
        new_version = datetime.datetime.now().strftime("%Y.%m.%d")
    if version is not None:
        new_version = version.rstrip(" ")
    else:
        new_version = run_shell_command_with_output(f"uv version --bump {part} --short --dry-run")

    # replace version according to pyproject.toml
    bump(new_version, dry_run=dry_run)

    run_shell_command("pixi lock" + dry_run)  # the version update should be reflected in pixi.lock
    run_shell_command("git add pixi.lock" + dry_run)

    run_shell_command(
        f"git commit -am 'chore(release): updated version to v{new_version}' --no-verify" + dry_run
    )
    if not dry_run:
        run_shell_command(f"git tag v{new_version}")
    run_shell_command("cz ch --incremental" + dry_run)  # generate changelog
    run_shell_command("git add CHANGELOG.md" + dry_run)
    run_shell_command(
        "git commit -am 'chore(changelog): incremental update of release changelog' --no-verify"
        + dry_run
    )
    if not dry_run:
        try:
            run_shell_command("git push" + dry_run)
            run_shell_command("git push --tags" + dry_run)
        except subprocess.CalledProcessError as err:
            LOGGER.info(
                "❌ Pushing failed. Did you configure remote? "
                "Please fix the error and continue with\n\n"
                "`git push && git push --tags`\n\nBacktrace:"
            )
            raise err
        LOGGER.info(
            "\n🚀 Publishing task sent to remote. "
            "See progress of remote launch @ "
            "https://gitlab.com/dboe/rna/-/pipelines\n"
        )
        log_changelog_extract()
        LOGGER.info(
            "\n✫ Use the above (↑) release-note to create a release @ "
            "https://gitlab.com/dboe/rna/-/releases"
        )


UNSET = "UNSET"


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format="%(message)s")
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--part",
        type=str,
        default=UNSET,
        help="The part of the version to be bumped. "
        f"Default is '{UNSET}' which is converted to 'part'",
    )
    parser.add_argument(
        "--version",
        type=str,
        default=UNSET,
        help="The version to be used. If set, part is ignored. "
        f"Default is '{UNSET}' which is converted to 'None'",
    )
    parser.add_argument(
        "--convention",
        type=str,
        default="semver",
        help="The version convention to be used. Default: semver, Options: semver, calver",
    )
    parser.add_argument(
        "--dry-run",
        action="store_true",
        default=False,
    )
    args = parser.parse_args()
    part_arg = args.part
    version_arg = args.version
    convention_arg = args.convention.lower()
    dry_run_arg = args.dry_run
    if version_arg == UNSET:
        version_arg = None
    if part_arg == UNSET:
        if version_arg is None:
            if convention_arg == "semver":
                part_arg = "patch"
            elif convention_arg == "calver":
                part_arg = "today"
        else:
            part_arg = None
    publish(part=part_arg, version=version_arg, dry_run=dry_run_arg)
