"""Le o relatorio do PHPStan e lista, por metodo, as chamadas estaticas a metodo de instancia
(Error no PHP 8) com: visibilidade, se o metodo usa $this e onde e chamado.

Uso: python estaticos.py <phpstan.json>
"""
import collections
import json
import re
import sys
from pathlib import Path

RAIZ = Path(__file__).resolve().parents[2]
BS = chr(92)


def corpo_do_metodo(texto: str, metodo: str):
    m = re.search(r"(public|protected|private)\s+(static\s+)?function\s+" + metodo + r"\s*\(", texto)
    if not m:
        return None, None
    ini = texto.index("{", m.end())
    nivel, j = 1, ini + 1
    while nivel:
        nivel += {"{": 1, "}": -1}.get(texto[j], 0)
        j += 1
    return m, texto[ini:j]


def main():
    dados = json.loads(Path(sys.argv[1]).read_text(encoding="utf8"))
    alvos = collections.defaultdict(list)
    for arq, v in dados["files"].items():
        for msg in v["messages"]:
            if "Static call to instance method" in msg["message"]:
                alvo = msg["message"].split("method ")[1].split("(")[0]
                alvos[alvo].append(f"{arq.replace('/var/www/html/accia-php83/', '')}:{msg['line']}")
    for alvo, locais in sorted(alvos.items()):
        classe, metodo = alvo.split("::")
        rel = classe.replace("app" + BS, "", 1).replace(BS, "/") + ".php"
        texto = (RAIZ / rel).read_bytes().decode("latin-1")
        m, corpo = corpo_do_metodo(texto, metodo)
        if m is None:
            print(f"{alvo} NAO ENCONTRADO em {rel}")
            continue
        estatico = " static" if m.group(2) else ""
        print(f"{alvo} [{m.group(1)}{estatico}] usa_this={'$this' in corpo} chamadas={len(locais)} ex={locais[:3]}")


if __name__ == "__main__":
    main()
