import subprocess

from config import REWISE_DEV_PATH, REWISE_02_PATH


REWISE_STATUS_UNSET    = -1
REWISE_STATUS_OK       = 0


def getRewiseStatusString(status):
  wsError = status & 64
  status -= wsError

  statusMap = {
    -1: "UNSET",
     0: "OK",
     1: "ERROR_SYSTEM_IO",
     2: "ERROR_ARGS",
     3: "ERROR_INTERNAL",
     4: "ERROR_EOF",
     5: "ERROR_SEEK",
     6: "ERROR_VALUE",
     8: "ERROR_INVALID_PENE",
     9: "ERROR_NOT_PENE",
    10: "ERROR_NOT_WISE",
    16: "ERROR_INFLATE",
    17: "ERROR_PK_HEADER",
    18: "ERROR_CRC32",
    24: "ERROR_BRANCHING"
  }

  if status in statusMap:
    if wsError:
      return f"WS_{statusMap[status]}"
    return statusMap[status]
  else:
    return "SEGFAULT"


PARSE_TYPE_INT   = 1  # parse first int after text
PARSE_TYPE_STR   = 2  # parse text after match
PARSE_TYPE_MATCH = 3  # bool (True when match found)

DEV_STDERR_PARSE = {
  #attr name        parse type        match         default
  "isNe"         : (PARSE_TYPE_MATCH, "DEBUG: NE ", False),
  "isPk"         : (PARSE_TYPE_MATCH, "DEBUG: IsPkFormat: 1", False),
  "overlayOffset": (PARSE_TYPE_INT, "DEBUG: OverlayOffset: ", -1),
  "peBuild"      : (PARSE_TYPE_INT, "DEBUG: PE Build: ", 0),
  "langCount"    : (PARSE_TYPE_INT, "DEBUG: LanguageCount: ", -1),
  "overlayUnk2"  : (PARSE_TYPE_STR, "OverlayHeader.unknown_2              : ", ""),
  "scriptDeflateOffset": (PARSE_TYPE_INT, "DEBUG: scriptDeflateOffset: ", -1)
}

DEV_STDOUT_PARSE = {
  "wsHdrUnk22"   : (PARSE_TYPE_STR, "WiseScriptHeader.unknown_22  : ", ""),
  "scriptBuild"  : (PARSE_TYPE_INT, "WiseScriptHeader.datetime    : ", -1)
}


def getLinesFromBytes(the_bytes):
  for line in the_bytes.decode("utf-8", errors="replace").split("\n"):
    yield line


def parse(lines, parsedict):
  result = {}
  for line in lines:
    for opt in parsedict:
      ptype = parsedict[opt][0]
      tomatch = parsedict[opt][1]

      if line.startswith(tomatch):
        if ptype == PARSE_TYPE_INT:
          result.update({opt: int(line[len(tomatch):].split(" ")[0])})
        elif ptype == PARSE_TYPE_STR:
          result.update({opt: line[len(tomatch):].rstrip()})
        elif ptype == PARSE_TYPE_MATCH:
          result.update({opt: True})
        break

  for opt in parsedict:
    if opt not in result:
      result.update({opt: parsedict[opt][2]})

  return result


def genericRewiseStats(file, rewisePath, rewiseOp):
  r = subprocess.run([rewisePath, rewiseOp, file],
             capture_output=True,
             text=True, encoding="utf8")

  result = {
    "status": REWISE_STATUS_UNSET,
    "error": ""
  }

  if r.returncode == 0:
    result["status"] = REWISE_STATUS_OK
  elif r.returncode < 127:
    result["status"] = r.returncode

    error = ""
    errCount = 0
    for line in reversed(r.stderr.split("\n")):
      if line.startswith("ERROR:"):
        error += line + "\n"
        errCount += 1
        if errCount == 5:
          break;
    result["error"] = error # last lines
  else:
    result["status"] = r.returncode

  return (r, result)


def getRewiseDevVerifyStats(file):
  return genericRewiseStats(file, REWISE_DEV_PATH, "-Vd")[1]

def getRewiseDevListStats(file):
  return genericRewiseStats(file, REWISE_DEV_PATH, "-l")[1]

def getRewiseDevRawVerifyStats(file):
  return genericRewiseStats(file, REWISE_DEV_PATH, "--raw-verify")[1]

def getRewise02VerifyStats(file):
  return genericRewiseStats(file, REWISE_02_PATH, "-V")[1]

def getRewiseDevOtherStats(file):
  r = subprocess.run([REWISE_DEV_PATH, "-ld", file],
                     capture_output=True,
                     text=False)
  result = {"title": ""}
  result.update(parse(getLinesFromBytes(r.stderr), DEV_STDERR_PARSE))

  # This is extra, parse the title (inside WiseScript.bin)
  r = subprocess.run([REWISE_DEV_PATH, "-zd", file],
                     capture_output=True,
                     text=False)
  textsStart = False
  for line in getLinesFromBytes(r.stdout):
    if textsStart and line.startswith("Text: "):
      result.update({"title": line[6:].replace("\"", "")})
      break
    if line.startswith("WiseScript Texts"):
      textsStart = True

  result.update(parse(getLinesFromBytes(r.stdout), DEV_STDOUT_PARSE))

  return result

# For mass grepping
def debugPrint(file):
  subprocess.run([REWISE_DEV_PATH, "-zd", file],
                 capture_output=False)
