#!/usr/bin/env python
import subprocess
import os
import sys
import re
from urllib.parse import urlsplit

extract_line_regex = re.compile(r"(.*?)(?::([0-9]+))?(?::([0-9]+))?(:)?$")

main_editor = "nvim"
editors = [main_editor, "vim", "vi"]
real_editor = os.environ.get("REAL_EDITOR", None)
editor_command = main_editor
if real_editor is not None:
    editors.append(real_editor)
    editor_command = real_editor

def run(cmd, only_stdout=True):
    res = subprocess.run(cmd, capture_output=True, text=True, shell=True)
    if only_stdout:
        return str(res.stdout)
    else:
        return res

def find_pane(window):
    for editor in editors:
        pane = run(f"tmux list-panes -a -f '#{{&&:#{{==:#{{window_id}},{window}}},#{{==:#{{pane_current_command}},{editor}}}}}' -F '#{{pane_id}}'").strip();
        if pane != "":
            return pane

def create_pane(args):
    run(f'tmux split-window -h -P -F "#{{pane_id}}" {editor_command} {args}')

def find_or_create_pane(window, args):
    if pane := find_pane(window):
        # exit copy mode so we don't send these commands directly to tmux
        run(f"tmux send-keys -t {pane} -X cancel")
        # Escape for some reason doesn't get sent as the escape key if it shows up next to any other keys???
        run(f"tmux send-keys -t {pane} Escape")

        # note the space, this tells nvim not to save it in history
        run(f"tmux send-keys -t {pane} \": drop {args}\" Enter")
        run(f"tmux select-pane -t {pane} -Z")
    else:
        create_pane(args)

def split_line(filename):
    mtch = extract_line_regex.match(filename)
    file = mtch.group(1)
    line = mtch.group(2)
    column = mtch.group(3)

    url = urlsplit(line)
    if url.scheme == "file" and url.path != file:
        file = url.path

    file = os.path.abspath(file)

    print(f"opening {file}:{line}:{column}")
    return file, line, column

def join_line(filename, maybe_line, maybe_column):
    assert not (maybe_line is None and maybe_column is not None)

    if maybe_line is None:
        return filename

    if maybe_column is None:
        maybe_column = "0"

    return f"+normal!{maybe_line}G{maybe_column} {filename}"

def trim(arg):
    if arg.startswith("\"") and not arg.endswith("\""):
        arg = arg.lstrip("\"")
    if arg.endswith("\"") and not arg.startswith("\""):
        arg = arg.rstrip("\"")
    return arg.strip()

def editor_hax(filename):
    args = split_line(trim(filename))
    current_window = run("tmux display-message -p \"#{window_id}\"").strip();
    find_or_create_pane(current_window, join_line(*args))

def xdg_open(arg):
    subprocess.run(f"xdg-open {trim(arg)}", shell=True)

def xdg_open_proxy(*args):
    for arg in args:
        try:
            _file, line, _column = split_line(arg)
            if line is not None:
                editor_hax(arg)
            else:
                xdg_open(arg)
        except:
            xdg_open(arg)


def usage():
    print(f"usage: {sys.argv[0]} filename:(line):(column)")
    print("    Opens a file with line number and colum in the editor in another pane of the current tmux window")
    print(f"usage: {sys.argv[0]} xdg-open-proxy filename:(line):(column)")
    print("    Calls xdg-open on the given parameters. However, if any part contains a line number and or column, opens in nvim like editor-hax")
    exit(1)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        usage()
    elif sys.argv[1] == "xdg-open-proxy":
        if len(sys.argv) < 3:
            usage()
        else:
            xdg_open_proxy(*sys.argv[1:])
    elif len(sys.argv) > 2:
        usage()
    else:
        editor_hax(sys.argv[1])

