import subprocess
from zipfile import ZipFile, ZIP_DEFLATED as COMPRESS_TYPE
import shutil
import os
import tomllib
import json
from dataclasses import dataclass
import readline

cargo_manifest = tomllib.load(open("noita-proxy/Cargo.toml", "rb"))
version = cargo_manifest["package"]["version"]

print("Current version: ", version)

COMPRESS_LEVEL = 9

@dataclass
class PullRequest:
    number: int
    author: str
    title: str

    def __str__(self):
        return f"{self.title} by @{self.author} in #{self.number}"

def try_remove(path):
    try:
        os.remove(path)
    except FileNotFoundError:
        pass

class ReleaseNotes:
    def __init__(self):
        self.md = []
    
    def title(self, t):
        self.md.append(f"## {t}\n")

    def p(self, t):
        self.md.append(f"\n{t}\n")
    
    def l(self, t):
        self.md.append(f"- {t}")
    
    def gen_md(self):
        return "\n".join(self.md)

def call_parse_json(args):
    return json.loads(subprocess.check_output(args))

def check_release_exists(tag):
    print("Checking if release exists:", tag)
    ret = subprocess.call(["gh", "release", "view", tag])
    exists = ret == 0
    return exists

def get_last_release():
    return call_parse_json(["gh", "release", "view", "--json", "publishedAt,name"])

def get_pull_requests_from(date):
    parsed = call_parse_json(["gh", "pr", "list", "--state", "merged", "--search", "merged:>"+date, "--json", "number,title,author"])
    return [PullRequest(entry["number"], entry["author"]["login"], entry["title"]) for entry in parsed]

def extract_steam_redist():
    os.makedirs("target/tmp", exist_ok=True)
    with ZipFile("redist/steam_dylib.zip", "r") as steam_dylib_zip:
        steam_dylib_zip.extractall("target/tmp")

def make_release_assets():
    print("Compiling Noita Proxy...")

    os.chdir("noita-proxy")

    subprocess.run(["cross", "build", "--profile", "release-lto", "--target", "x86_64-unknown-linux-gnu"], check=True)
    subprocess.run(["cargo", "build", "--profile", "release-lto", "--target", "x86_64-pc-windows-gnu"], check=True)

    os.chdir("..")

    os.makedirs("target", exist_ok=True)
    os.makedirs("target/tmp", exist_ok=True)

    try_remove("target/noita-proxy-win.zip")
    try_remove("target/noita-proxy-linux.zip")
    try_remove("target/quant.ew.zip")

    print("Extracting steam dylib...")

    extract_steam_redist()

    print("Writing win release...")

    with ZipFile("target/noita-proxy-win.zip", "w") as release:
        release.write("noita-proxy/target/x86_64-pc-windows-gnu/release-lto/noita-proxy.exe", arcname="noita_proxy.exe", compress_type=COMPRESS_TYPE, compresslevel=COMPRESS_LEVEL)
        release.write("target/tmp/steam_api64.dll", arcname="steam_api64.dll", compress_type=COMPRESS_TYPE, compresslevel=COMPRESS_LEVEL)

    print("Writing linux release...")

    with ZipFile("target/noita-proxy-linux.zip", "w") as release:
        release.write("noita-proxy/target/x86_64-unknown-linux-gnu/release-lto/noita-proxy", arcname="noita_proxy.x86_64", compress_type=COMPRESS_TYPE, compresslevel=COMPRESS_LEVEL)
        release.write("target/tmp/libsteam_api.so", arcname="libsteam_api.so", compress_type=COMPRESS_TYPE, compresslevel=COMPRESS_LEVEL)

    print("Writing mod release...")

    shutil.make_archive("target/quant.ew", "zip", "quant.ew")

    with ZipFile("target/quant.ew.zip", "a") as release:
        release.writestr("files/version.lua", f'return "{version}"')

def main():
    tag = "v"+version
    if check_release_exists(tag):
        print("Release already exists, exiting")
        exit(1)

    subprocess.run(["git", "pull"])
    subprocess.run(["git", "commit", "-am", "Automated commit: "+tag])
    subprocess.run(["git", "push"])

    last_release = get_last_release()
    print("Last release is:", last_release["name"])

    pull_requests = get_pull_requests_from(last_release["publishedAt"])
    print()

    make_release_assets()

    print()
    print("Will release:", tag)
    print("Accepted pull requests:")

    for request in pull_requests:
        print(request)

    print()

    notes = ReleaseNotes()

    notes.title("Noita Entangle Worlds "+tag)

    notes.p("")

    notes.title("Accepted pull requests")
    if pull_requests:
        for request in pull_requests:
            notes.l(request)
    else:
        notes.p("No pull requests have been accepted in this release.")

    notes.title("Installation")
    notes.p("Download and unpack `noita-proxy-win.zip` or `noita-proxy-linux.zip`, depending on your OS. After that, launch the proxy.")
    notes.p("Proxy is able to download and install the mod automatically. There is no need to download the mod (`quant.ew.zip`) manually.")
    notes.p("""You'll be prompted for a path to `noita.exe` when launching the proxy for the first time. 
It should be detected automatically as long as you use steam version of the game and steam is launched.
        """)
    
    notes.title("Updating")
    notes.p("There is a button in bottom-left corner on noita-proxy's main screen that allows to auto-update to a new version when one is available")

    print()
    notes_path = "/tmp/rnotes.md"
    with open(notes_path, "w") as f:
        print(notes.gen_md(), file=f)
    
    subprocess.check_call(["nano", notes_path])

    title = input("Release title: ")

    subprocess.call(["gh", "release", "create", tag, "--title", f"{tag} - {title}", "-F", notes_path, "./target/noita-proxy-linux.zip", "./target/noita-proxy-win.zip", "./target/quant.ew.zip"])

if __name__ == "__main__":
    main()
