# Uruchomiony 29.09.2026. Ocena odpowiedzi: numery z odpowiedzi porównane ze zbiorem numerów z oficjalnej strony marki (marki.json).
import json,re,os,sys,collections
KAT=os.path.dirname(os.path.abspath(__file__))
MARKI={m["marka"]:m for m in json.load(open(KAT+"/marki.json"))}
POLA_PROBY=("marka","asystent","wariant","powtorzenie")
KOREKTY={tuple(k[p] for p in POLA_PROBY):k for k in json.load(open(KAT+"/korekty-reczne.json"))}
def domeny(t): return [re.sub(r"^www\.","",u.split("/")[2].lower()) for u in re.findall(r"https?://[^\s)\]]+",t)]
def z_marki(d,marka): return any(d==q or d.endswith("."+q) for q in MARKI[marka]["domeny"])
def numery(t):
    t=t.replace("\u00a0"," ").replace("**","").replace("__","")
    wyn=set()
    for m in re.finditer(r"\*\s?(\d{3})\b",t): wyn.add("*"+m.group(1))
    for m in re.finditer(r"(?<![\d.,:])(\+?\(?\d[\d \-\(\)]{3,17}\d)(?!\d)",t):
        zapis=m.group(1).lstrip("("); d=re.sub(r"\D","",zapis)
        z_prefiksem=zapis.startswith("+48")  # jawny prefiks kraju odcinamy zawsze, cyfr po nim nie poprawiamy
        if z_prefiksem or (len(d)==11 and d.startswith("48")): d=d[2:]
        if len(d)==10 and d.startswith("0"): d=d[1:]
        if len(d)==9 or re.fullmatch(r"19\d{3}",d) or (z_prefiksem and len(d)==7): wyn.add(d)  # 19xxx to polskie numery skrócone
    return wyn
def ocena(w, korekty=True):
    ofic=set(MARKI[w["marka"]]["oficjalne"]); znal=numery(w["odpowiedz"])
    if w["blad"]: return "blad",znal,set()
    korekta=KOREKTY.get(tuple(w[p] for p in POLA_PROBY)) if korekty else None
    if korekta:
        for zapis in korekta["zapisy"]:
            if zapis not in w["odpowiedz"]:
                raise ValueError(f"Brak zapisu z korekty w odpowiedzi: {zapis}")
            # Usuwamy jedynie formatowanie i jawny prefiks kraju (gwiazdkę kodu zostawiamy), nie naprawiamy cyfr.
            znal.add(("*" if zapis.startswith("*") else "")+re.sub(r"\D","",re.sub(r"^\+48\s*","",zapis)))
    obce=znal-ofic
    if not znal: kat="bez numeru"
    elif not obce: kat="zgodny"
    elif znal&ofic: kat="czesciowo"
    else: kat="niezgodny"
    return kat,znal,obce
if __name__=="__main__":
    W=json.load(open(KAT+"/odpowiedzi.json"))
    if not set(KOREKTY)<=set(tuple(w[p] for p in POLA_PROBY) for w in W):
        raise ValueError("Korekta nie ma odpowiadającej jej próby")
    wyn=[]
    for w in W:
        kat,znal,obce=ocena(w); d=domeny(w["odpowiedz"])
        wys=None if (w["asystent"]=="claude-sonnet-5-5" and w["wariant"]=="wyszukiwanie") else w["wyszukiwania"]  # raport Claude Code nie liczy narzędzia WebSearch; źródła widać w odpowiedzi
        wyn.append({**{k:w[k] for k in ("marka","asystent","wariant","powtorzenie")},"wyszukiwania":wys,"kategoria":kat,"numery":sorted(znal),"spoza_strony":sorted(obce),"zrodla":sorted(set(d)),"zrodlo_ze_strony_marki":any(z_marki(x,w["marka"]) for x in d),"zrodlo_spoza_marki":any(not z_marki(x,w["marka"]) for x in d)})
        korekta=KOREKTY.get(tuple(w[p] for p in POLA_PROBY))
        if korekta:
            kat_auto,znal_auto,_=ocena(w,korekty=False)
            wyn[-1].update({"kategoria_automatyczna":kat_auto,"numery_automatyczne":sorted(znal_auto),"korekta_reczna":korekta["uzasadnienie"]})
        inne=MARKI[w["marka"]].get("inne_numery_ze_strony_marki",{})
        if obce and set(obce)<=set(inne): wyn[-1]["uwaga"]="Numer spoza strony kontaktowej, ale z innej strony marki: "+", ".join(inne[n] for n in sorted(obce))
    json.dump(wyn,open(KAT+"/ocena.json","w"),ensure_ascii=False,indent=1)
    c=collections.Counter((x["asystent"],x["wariant"],x["kategoria"]) for x in wyn)
    for (a,v,k),n in sorted(c.items()): print(f"{a:18} {v:13} {k:12} {n}")
