#!/usr/bin/python3

import json
import logging
import platform
import shlex
import shutil
import struct
import subprocess
import sys
from pathlib import Path

# We assume that this python script is located in "jabref/lib" while the executable is "jabref/bin/JabRef"
# Note that the package structure is different when installed as a .app bundle on MacOs, so the path must be altered.
script_dir = Path(__file__).resolve().parent.parent
JABREF_PATH = script_dir / "bin/JabRef"

# on mac we must only go one folder upwards
if sys.platform.startswith('darwin'):
    script_dir = Path(__file__).resolve().parent
if not JABREF_PATH.exists():
    JABREF_PATH = script_dir / "MacOS/JabRef"

if not JABREF_PATH.exists():
    logging.error("Could not determine JABREF_PATH")
    send_message({"message": "error", "output": "Could not find JabRef. Please check that it is installed correctly."})
    sys.exit(-1)

logging_dir = Path.home() / ".mozilla/native-messaging-hosts/"
if not logging_dir.exists():
    logging_dir.mkdir(parents=True)
logging.basicConfig(filename=str(logging_dir / "jabref_browser_extension.log"))

# Read a message from stdin and decode it.
def get_message():
    raw_length = sys.stdin.buffer.read(4)
    if not raw_length:
        logging.error("Raw_length null")
        sys.exit(0)
    message_length = struct.unpack("=I", raw_length)[0]
    logging.info("Got length: {} bytes to be read".format(message_length))
    message = sys.stdin.buffer.read(message_length).decode("utf-8")
    logging.info("Got message of {} chars".format(len(message)))
    data = json.loads(message)
    logging.info("Successfully retrieved JSON")
    return data


# Encode a message for transmission, given its content.
def encode_message(message_content):
    encoded_content = json.dumps(message_content).encode("utf-8")
    encoded_length = struct.pack("=I", len(encoded_content))
    return {
        "length": encoded_length,
        "content": struct.pack(str(len(encoded_content)) + "s", encoded_content),
    }


# Send an encoded message to stdout.
def send_message(message):
    encoded_message = encode_message(message)
    sys.stdout.buffer.write(encoded_message["length"])
    sys.stdout.buffer.write(encoded_message["content"])
    sys.stdout.buffer.flush()


def add_jabref_entry(data):
    """Send string via cli as literal to preserve special characters"""
    cmd = str(JABREF_PATH).split() + ["--importBibtex", r"{}".format(data)]
    logging.info("Try to execute command {}".format(cmd))
    response = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
    logging.info("Called JabRef and got: {}".format(response))
    return response


logging.info("Starting JabRef backend")

try:
    message = get_message()
except Exception as e:
    message = str(e)
logging.info(str(message))

if "status" in message and message["status"] == "validate":
    cmd = str(JABREF_PATH).split() + ["--version"]
    try:
        response = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as exc:
        logging.error("Failed to call JabRef: {} {}".format(exc.returncode, exc.output))
        send_message({"message": "jarNotFound", "path": JABREF_PATH})
    else:
        logging.info("Response: {}".format(response))
        send_message({"message": "jarFound"})
else:
    entry = message["text"]
    try:
        output = add_jabref_entry(entry)
        send_message({"message": "ok", "output": str(output)})
    except subprocess.CalledProcessError as exc:
        logging.error("Failed to call JabRef: {} {}".format(exc.returncode, exc.output))
        send_message({"message": "error", "output": str(exc.output)})
