"""
sbbot — SofaScore günlük maç havuzu çekici (3. aşama sonuç kaynağı).

PHP tarafı SofaScore'a doğrudan gidemiyor (TLS/JA3 kontrolü → 403). curl_cffi Chrome'un
TLS el sıkışmasını taklit ettiği için geçiyor — çekim Python tarafında.

Kullanım:
    python sofa_cek.py 2026-07-24 --spor football --cikti out.json --ilerleme prog.json
    --ulke-adlari "USA,Brazil,South Korea"   → sadece bu ülkelerin ligleri (İngilizce ad)
    --tz 10800                                → saat dilimi (varsayılan +03)

Akış: scheduled-tournaments/{tarih}/page/N (ülke=category adı ile süz) → unique-tournament/{id}/scheduled-events/{tarih}
Çıktı: {ok, tarih, mac_sayisi, maclar:[{id,ts,lig,ulke,ev,dep,ev_slug,dep_slug,durum,ms_ev/ms_dep,iy_ev/iy_dep,...}]}
"""

import difflib
import json
import os
import re
import sys
import time
import unicodedata

try:
    from curl_cffi import requests
except ImportError:
    print(json.dumps({"ok": False, "hata": "curl_cffi kurulu degil: python -m pip install curl_cffi"}))
    sys.exit(1)

API = "https://www.sofascore.com/api/v1"
SPOR = "football"
BASLIK = {
    "accept": "*/*",
    "accept-language": "tr-TR,tr;q=0.9,en-US;q=0.8",
    "referer": "https://www.sofascore.com/",
    "x-requested-with": "312d2d",
}
BEKLE = 0.25
SAYFA_SINIRI = 12
ILERLEME_DOSYA = None

# Ülke adı normalize + bilinen farklar (bizim ad → SofaScore kategori adı normali)
ALIAS = {
    "republicofkorea": "southkorea", "korearepublic": "southkorea", "korea": "southkorea",
    "unitedstates": "usa", "usa": "usa", "unitedstatesofamerica": "usa",
    "czechrepublic": "czechia", "czechia": "czechia",
    "bosniaandherzegovina": "bosniaherzegovina",
    "unitedarabemirates": "uae", "uae": "uae",
    "chinapr": "china", "irans": "iran",
    "northmacedonia": "macedonia", "macedonia": "macedonia",
    # SportyBet "Turkiye" yazıyor, SofaScore kategorisi "Turkey" → normaller (turkiye/turkey)
    # tutmuyordu ve TÜM Türkiye ligleri havuza HİÇ girmiyordu. "Pendikspor - Batman Petrolspor
    # SofaScore'da var ama bulamıyoruz" vakasının sebebi buydu: eşleştirme değil, ÇEKİM kaçırıyordu.
    # 89 futbol ülkesi kategori listesine karşı denetlendi; tek gerçek uyuşmazlık buydu.
    "turkiye": "turkey", "turkey": "turkey",
    # ── stakebot: Stake feed'i TÜRKÇE ülke adı veriyor (Ekvador/Arjantin/Brezilya…), SofaScore kategorisi
    #    İngilizce. _norm sonrası TR ad → EN ad. (Mısır→"msr", Şili→"sili" aksan katlamasına dikkat.) ──
    "arjantin": "argentina", "brezilya": "brazil", "ekvador": "ecuador", "sili": "chile",
    "kolombiya": "colombia", "bolivya": "bolivia", "meksika": "mexico", "kostarika": "costarica",
    "kanada": "canada", "jamaika": "jamaica", "abd": "usa", "amerika": "usa",
    "almanya": "germany", "ispanya": "spain", "italya": "italy", "fransa": "france",
    "ingiltere": "england", "iskocya": "scotland", "galler": "wales", "irlanda": "ireland",
    "hollanda": "netherlands", "belcika": "belgium", "portekiz": "portugal", "yunanistan": "greece",
    "rusya": "russia", "ukrayna": "ukraine", "polonya": "poland", "romanya": "romania",
    "bulgaristan": "bulgaria", "cekya": "czechia", "cekcumhuriyeti": "czechia", "slovakya": "slovakia",
    "macaristan": "hungary", "avusturya": "austria", "isvicre": "switzerland", "danimarka": "denmark",
    "isvec": "sweden", "norvec": "norway", "finlandiya": "finland", "izlanda": "iceland",
    "hirvatistan": "croatia", "sirbistan": "serbia", "slovenya": "slovenia", "bosnahersek": "bosniaherzegovina",
    "karadag": "montenegro", "kuzeymakedonya": "macedonia", "arnavutluk": "albania", "kibris": "cyprus",
    "luksemburg": "luxembourg", "estonya": "estonia", "letonya": "latvia", "litvanya": "lithuania",
    "gurcistan": "georgia", "ermenistan": "armenia", "azerbaycan": "azerbaijan", "kazakistan": "kazakhstan",
    "japonya": "japan", "guneykore": "southkorea", "cin": "china", "hindistan": "india",
    "endonezya": "indonesia", "tayland": "thailand", "malezya": "malaysia", "suudiarabistan": "saudiarabia",
    "katar": "qatar", "birlesikarapemirlikleri": "uae", "irak": "iraq", "msr": "egypt",
    "fas": "morocco", "cezayir": "algeria", "tunus": "tunisia", "guneyafrika": "southafrica",
    "nijerya": "nigeria", "kamerun": "cameroon", "fildisisahili": "ivorycoast", "israil": "israel",
    "yenizelanda": "newzealand", "avustralya": "australia",
}

# Kıta-üstü etiketlerimizin SofaScore'da TEK karşılığı yok — turnuvaya göre farklı kategoride:
#   CONMEBOL Libertadores/Sudamericana → "South America"
#   UEFA Şampiyonlar Ligi / Avrupa Ligi → "Europe"
#   Dünya Kupası, kulüp hazırlık maçları → "World"   (flag'i "international")
# Ayrıca bizim "International" adı SofaScore'da "World" diye geçiyor, yani düz ad eşleşmesi
# ikisinde de BOŞ dönüyordu ve bu ligler hiç taranmıyordu (Libertadores hep kayıptı).
# Bu yüzden bu etiketler ad→ad değil, ad→KATEGORİ ADI LİSTESİ olarak eşlenir; flag'ler
# categories yanıtından çözülür (flag dizesini elle yazmak kırılgan olurdu).
KITA_KATEGORILERI = ["World", "South America", "Europe", "Africa", "Asia", "Oceania",
                     "North & Central America"]
COK_KATEGORI = {
    "international":      KITA_KATEGORILERI,
    "internationalclubs": KITA_KATEGORILERI,
    "internationalyouth": KITA_KATEGORILERI,
}


def _norm(s):
    """Karşılaştırma normali. AKSANLARI KATLAR: "Primera División" ve "Primera Division"
    aynı diziye iner. Eskiden aksanlı harf tamamen siliniyordu ("División"→"divisin",
    "Türkiye"→"trkiye") ve doğru lig/ülke asla eşleşmiyordu."""
    s = unicodedata.normalize("NFKD", (s or ""))
    s = "".join(c for c in s if not unicodedata.combining(c))
    return re.sub(r"[^a-z]", "", s.lower())


def _ulke_normset(adlar):
    out = set()
    for a in adlar:
        n = _norm(a)
        out.add(ALIAS.get(n, n))
    return out


def ilerleme_yaz(**kw):
    if not ILERLEME_DOSYA:
        return
    try:
        with open(ILERLEME_DOSYA, "w", encoding="utf-8") as f:
            json.dump(kw, f, ensure_ascii=False)
    except Exception:
        pass


PROXY_DOSYA = os.path.join(os.path.dirname(os.path.abspath(__file__)), "proxies.json")


def proxyleri_yukle():
    try:
        with open(PROXY_DOSYA, encoding="utf-8") as f:
            v = json.load(f)
        return [p for p in (v.get("proxies") if isinstance(v, dict) else v) if p]
    except Exception:
        return []


PROXYLER = proxyleri_yukle()
_sayac = {"i": 0}
ISTATISTIK = {}


def _sonraki_proxy():
    if not PROXYLER:
        return None
    p = PROXYLER[_sayac["i"] % len(PROXYLER)]
    _sayac["i"] += 1
    return p


def _kaydet(p, ok, mesaj=""):
    if not p:
        return
    d = ISTATISTIK.setdefault(p, {"basari": 0, "hata": 0, "son_hata": ""})
    if ok:
        d["basari"] += 1
    else:
        d["hata"] += 1
        d["son_hata"] = mesaj[:120]


ISTEK = {"cagri": 0, "http": 0}   # cagri = cek() çağrısı · http = gerçekte atılan istek (tekrarlar dahil)


def cek(url, deneme=None):
    ISTEK["cagri"] += 1
    deneme = deneme or (min(4, len(PROXYLER)) if PROXYLER else 2)
    for _ in range(deneme):
        p = _sonraki_proxy()
        ISTEK["http"] += 1
        try:
            r = requests.get(url, headers=BASLIK, impersonate="chrome", timeout=30,
                             proxies=({"http": p, "https": p} if p else None))
            if r.status_code == 200:
                _kaydet(p, True)
                return r.json()
            if r.status_code == 404:
                _kaydet(p, True)
                return None
            _kaydet(p, False, f"HTTP {r.status_code}")
        except Exception as e:
            _kaydet(p, False, str(e))
        time.sleep(0.4)
    return None


def flags_from_names(adlar):
    """İstenen İngilizce ülke adlarını SofaScore categories'ten flag'lere çevir (id iki uçta farklı, flag tutarlı).
    7 gün cache: cache/_cat_{spor}.json."""
    cd = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache", f"_cat_{SPOR}.json")
    cats = None
    try:
        if time.time() - os.path.getmtime(cd) < 7 * 86400:
            with open(cd, encoding="utf-8") as f:
                cats = json.load(f)
    except Exception:
        pass
    if cats is None:
        j = cek(f"{API}/sport/{SPOR}/categories")
        cats = [{"name": c.get("name"), "flag": c.get("flag"), "a2": (c.get("alpha2") or "")}
                for c in (j.get("categories", []) if j else []) if c.get("flag")]
        if cats:
            try:
                with open(cd, "w", encoding="utf-8") as f:
                    json.dump(cats, f)
            except Exception:
                pass
    want = _ulke_normset(adlar)
    flags = set()
    for c in cats:
        if ALIAS.get(_norm(c["name"]), _norm(c["name"])) in want:
            flags.add(c["flag"])
    # Kıta-üstü etiketler: bir ad → birden çok kategori (bkz. COK_KATEGORI)
    ek = {_norm(a) for w in want for a in COK_KATEGORI.get(w, ())}
    if ek:
        for c in cats:
            if _norm(c["name"]) in ek:
                flags.add(c["flag"])
    return flags


def turnuvalar(tarih, tz, ulke_flag=None, ulke_norm=None):
    """Günün turnuva listesi. Süzgeç HEM flag HEM kategori ADI ile çalışır.

    NEDEN ikisi birden: /sport/{spor}/categories ucu TÜM ülkeleri döndürmüyor — basketbolda
    yalnız 81 kategori geliyor ve Paraguay, Peru, Ekvador YOK. O yüzden "Paraguay" istendiğinde
    flag çözülemiyor, ülke sessizce eleniyor ve LNB maçları (Colonias Gold - Olimpia Kings)
    havuza hiç girmiyordu. Oysa GÜNLÜK LİSTE kategori adını zaten taşıyor; ada bakmak
    kategori ucundan bağımsız ve daha güvenilir. Flag yolu da korunuyor (ad farklılıklarında
    ALIAS yetmezse flag tutabilir)."""
    bulunan, sayfa = {}, 1
    suz = (ulke_flag is not None) or bool(ulke_norm)
    while sayfa <= SAYFA_SINIRI:
        ilerleme_yaz(asama="turnuva-listesi", sayfa=sayfa,
                     mesaj=f"Turnuva listesi çekiliyor — sayfa {sayfa}", turnuva=len(bulunan))
        j = cek(f"{API}/sport/{SPOR}/scheduled-tournaments/{tarih}/page/{sayfa}")
        if not j:
            break
        for t in j.get("scheduled", []):
            T = t.get("tournament") or {}
            u = T.get("uniqueTournament") or {}
            if u.get("id") is None:
                continue
            if suz:
                cat = T.get("category") or {}
                fl  = cat.get("flag")
                nm  = _norm(cat.get("name"))
                nm  = ALIAS.get(nm, nm)
                if not ((ulke_flag and fl in ulke_flag) or (ulke_norm and nm in ulke_norm)):
                    continue
            adet = int((t.get("timezoneEventCount") or {}).get(tz, 0))
            if adet > 0:
                bulunan[u["id"]] = max(bulunan.get(u["id"], 0), adet)
        if not j.get("hasNextPage"):
            break
        sayfa += 1
        time.sleep(BEKLE)
    return bulunan, sayfa


def _lig_map_yol():
    return os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache", f"_lig_map_{SPOR}.json")


def lig_map_oku():
    try:
        with open(_lig_map_yol(), encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return {}


def lig_map_yaz(m):
    try:
        with open(_lig_map_yol(), "w", encoding="utf-8") as f:
            json.dump(m, f, ensure_ascii=False)
    except Exception:
        pass


def lig_ara(lig_ad, ulke_ad):
    """Bir ligin SofaScore uniqueTournament ADAYLARINI arama ucundan bul (skora göre sıralı).

    NEDEN gerekli: /sport/{spor}/scheduled-tournaments/{tarih} dizini EKSİK. Paraguay LNB
    (uniqTid 26299) hiçbir tarihte listelenmiyor ama /unique-tournament/26299/scheduled-events
    maçları veriyor. Yani dizin "öne çıkanlar" gibi davranıyor; küçük ligler dışarıda kalıyor
    ve o maçlar havuza hiç girmediği için "SofaScore'da var, biz bulamıyoruz" oluyordu.

    TEK ID DEĞİL LİSTE döner çünkü ad benzerliği yanıltıyor: "Primera Division" araması
    Uruguay'da hem 18000 "Primera Division" (doğru) hem 20023 "Primera Divisional C"
    (alt lig) getiriyor ve alt-dize eşleşmesi yanlışını seçebiliyordu. Çağıran, adayları
    sırayla deneyip O TARİHTE MAÇ DÖNENİ seçer — asıl doğrulama budur.
    Sorguya ÜLKE de eklenir: yalnız lig adıyla arayınca doğru turnuva ilk sayfaya girmiyordu."""
    hedef_ulke = _norm(ulke_ad)
    hedef_ulke = ALIAS.get(hedef_ulke, hedef_ulke)
    hedef_lig = _norm(lig_ad)
    bulunan = {}
    try:
        from urllib.parse import quote
    except Exception:
        return []
    for sorgu in (f"{lig_ad} {ulke_ad}", lig_ad):
        j = cek(f"{API}/search/all?q={quote(sorgu)}&page=0")
        for r in (j or {}).get("results", []):
            if r.get("type") not in ("uniqueTournament", "tournament"):
                continue
            e = r.get("entity") or {}
            cat = e.get("category") or {}
            if ((cat.get("sport") or {}).get("name") or "").strip().lower() != SPOR:
                continue
            cn = _norm(cat.get("name"))
            if ALIAS.get(cn, cn) != hedef_ulke:
                continue
            an = _norm(e.get("name"))
            if not an or not e.get("id"):
                continue
            # TAM eşleşme her zaman önde; değilse dizi benzerliği (alt-dize KULLANILMAZ:
            # "primeradivision" ⊂ "primeradivisionalc" yanlış ligi seçtiriyordu)
            s = 1.0 if an == hedef_lig else difflib.SequenceMatcher(None, an, hedef_lig).ratio() * 0.9
            tid = int(e["id"])
            if s > bulunan.get(tid, 0):
                bulunan[tid] = s
        time.sleep(BEKLE)
    return [t for t, s in sorted(bulunan.items(), key=lambda x: -x[1]) if s >= 0.6][:4]


# Kulüp kısaltmaları — takım adı karşılaştırmasında ATILIR. Sağlayıcılar bunları keyfî
# ekleyip çıkarıyor: bizde "CA Boston River"/"Danubio FC", SofaScore'da "Boston River"/"Danubio".
# Bunları temizlemeden benzerlik ölçünce yanlış takım seçilebiliyor (264395 ≠ 174970).
KULUP_EK = {
    "fc", "afc", "cfc", "sc", "ac", "as", "ca", "cd", "cf", "cp", "sd", "ud", "rc", "rcd",
    "sk", "fk", "nk", "hk", "kk", "bk", "if", "sv", "tsv", "vfb", "vfl", "us", "ssc", "ss",
    "gks", "ks", "mks", "lks", "club", "clube", "kulubu", "spor", "sport", "sports",
}


def _takim_norm(ad):
    """Takım adı normali: kulüp kısaltmaları atılır, aksan katlanır."""
    s = unicodedata.normalize("NFKD", (ad or ""))
    s = "".join(c for c in s if not unicodedata.combining(c)).lower()
    parca = [p for p in re.split(r"[^a-z0-9]+", s) if p]
    kalan = [p for p in parca if p not in KULUP_EK]
    return "".join(kalan or parca)          # her şey kısaltmaysa ham hâlini kullan


def takim_ara(ad):
    """Takım adından SofaScore takım id'si (yoksa None). Aynı spordaki en iyi ad eşleşmesi."""
    try:
        from urllib.parse import quote
    except Exception:
        return None
    hedef = _takim_norm(ad)
    en_id, en_skor = None, 0.0
    for sorgu in (ad, hedef):               # ham ad tutmazsa sadeleşmiş adla bir daha ara
        j = cek(f"{API}/search/all?q={quote(sorgu)}&page=0")
        for r in (j or {}).get("results", []):
            if r.get("type") != "team":
                continue
            e = r.get("entity") or {}
            if ((e.get("sport") or {}).get("name") or "").strip().lower() != SPOR:
                continue
            an = _takim_norm(e.get("name"))
            if not an or not e.get("id"):
                continue
            s = 1.0 if an == hedef else difflib.SequenceMatcher(None, an, hedef).ratio()
            if s > en_skor:
                en_skor, en_id = s, int(e["id"])
        if en_skor >= 0.999:                # tam eşleşme bulundu, ikinci sorguya gerek yok
            break
        time.sleep(BEKLE)
    return en_id if en_skor >= 0.78 else None


def eksik_maclari_ekle(mac_listesi, havuz, tarih):
    """Havuzda karşılığı ÇIKMAYAN maçlarımızı TAKIM ucundan bul ve ekle.

    NEDEN takım (lig değil): sağlayıcılar lig adlarında hiç uyuşmuyor — Uruguay üst ligine
    biz "Primera Division", SofaScore "Liga AUF Uruguaya" diyor; ad benzerliği sıfır, lig
    araması bunu ASLA bulamaz (üstelik "Primera Division" araması Uruguay'da futsal ligleri
    ve alt lig "Primera Divisional C"yi getirip yanlış eşleşme üretiyordu). Takım adları ise
    sağlayıcılar arasında birbirine yakın ("Boston River" ↔ "Boston River").
    /team/{id}/events/last/0 maçı turnuvasıyla birlikte veriyor; günlük dizin eksik olsa da
    (Paraguay LNB, Liga AUF) maç buradan geliyor.

    mac_listesi: ["Ev|Deplasman", …] · Dönüş: eklenen maç satırları."""
    if not mac_listesi:
        return []
    var = [(_takim_norm(m.get("ev")), _takim_norm(m.get("dep"))) for m in havuz]

    # GÜN SINIRI TOLERANSI: SofaScore startTimestamp UTC; takımın maçı SUNUCU YEREL saatinde
    # komşu güne düşebilir (Honduras UTC-6 gibi ülkelerde). Bu yüzden takım-olaylarını "tam o gün"
    # yerine tarih ±1 GÜN al. Kesin zaman eşleşmesini PHP (sf_en_iyi_aday) tolDk ile yaptığı için
    # gerçekten alakasız (24s uzak) maçlar orada zaten elenir → yanlış eşleşme riski yok.
    import datetime as _dt
    try:
        _hedef = _dt.datetime.strptime(tarih, "%Y-%m-%d").date()
        _gecerli_gunler = {(_hedef + _dt.timedelta(days=o)).strftime("%Y-%m-%d") for o in (-1, 0, 1)}
    except Exception:
        _gecerli_gunler = {tarih}

    harita = lig_map_oku()          # "takım adı" → SofaScore takım id (None = bulunamadı)
    degisti = False
    eklenen, gorulen_id = [], {m.get("id") for m in havuz}

    for i, satir in enumerate(mac_listesi, 1):
        if "|" not in satir:
            continue
        ev, dep = [x.strip() for x in satir.split("|", 1)]
        en, dn = _takim_norm(ev), _takim_norm(dep)
        # bu maç havuzda var mı? (takım adları yeterince benziyorsa var say)
        def benzer(a, b):
            return a == b or (a and b and difflib.SequenceMatcher(None, a, b).ratio() >= 0.75)
        if any(benzer(en, e) and benzer(dn, d) for e, d in var):
            continue

        ilerleme_yaz(asama="eksik-maclar",
                     mesaj=f"Dizinde olmayan maç aranıyor — {ev} - {dep} ({i}/{len(mac_listesi)})")
        tid = None
        for ad in (ev, dep):                       # ev takımı tutmazsa deplasmanı dene
            anahtar = "T:" + ad
            if anahtar in harita:
                tid = harita[anahtar]
            else:
                tid = takim_ara(ad)
                harita[anahtar] = tid              # None da yazılır → her gün boşuna aranmaz
                degisti = True
                time.sleep(BEKLE)
            if tid:
                break
        if not tid:
            continue

        j = cek(f"{API}/team/{tid}/events/last/0")
        time.sleep(BEKLE)
        for e in (j or {}).get("events", []):
            if e.get("id") in gorulen_id:
                continue
            ts = e.get("startTimestamp")
            if not ts or time.strftime("%Y-%m-%d", time.localtime(ts)) not in _gecerli_gunler:
                continue                            # istenen gün ±1 (saat dilimi sınırı toleransı)
            r = mac_parse(e)
            eklenen.append(r)
            gorulen_id.add(e.get("id"))
            var.append((_takim_norm(r.get("ev")), _takim_norm(r.get("dep"))))

    if degisti:
        lig_map_yaz(harita)
    return eklenen


def skor(d):
    nt = d.get("normaltime")
    return {
        "ms": nt if nt is not None else d.get("current"),
        "iy": d.get("period1"), "y2": d.get("period2"),
        "nt": nt, "uzatma": d.get("overtime"), "penalti": d.get("penalties"),
    }


def skor_basket(d):
    q1, q2, q3, q4 = d.get("period1"), d.get("period2"), d.get("period3"), d.get("period4")
    iy = (q1 or 0) + (q2 or 0) if (q1 is not None or q2 is not None) else None
    return {"ms": d.get("current"), "iy": iy, "q1": q1, "q2": q2, "q3": q3, "q4": q4, "uzatma": d.get("overtime")}


def mac_parse(e):
    """Tek bir SofaScore event nesnesini havuz satırına çevir.
    Hem turnuva ucundan hem TAKIM ucundan gelen event'ler aynı şekilde ayrıştırılır."""
    if True:
        T = e.get("tournament") or {}
        ts = e.get("startTimestamp")
        r = {
            "id": e.get("id"), "ts": ts,
            "tarih_saat": time.strftime("%Y-%m-%d %H:%M", time.localtime(ts)) if ts else None,
            "lig": T.get("name"), "lig_id": (T.get("uniqueTournament") or {}).get("id"),
            "ulke": ((T.get("category") or {}).get("name")),
            "ev": (e.get("homeTeam") or {}).get("name"), "dep": (e.get("awayTeam") or {}).get("name"),
            "ev_slug": (e.get("homeTeam") or {}).get("slug"), "dep_slug": (e.get("awayTeam") or {}).get("slug"),
            "durum": (e.get("status") or {}).get("type"), "durum_ad": (e.get("status") or {}).get("description"),
        }
        hd, ad = e.get("homeScore") or {}, e.get("awayScore") or {}
        if SPOR == "basketball":
            h, a = skor_basket(hd), skor_basket(ad)
            r.update({
                "ms_ev": h["ms"], "ms_dep": a["ms"], "iy_ev": h["iy"], "iy_dep": a["iy"],
                "q1_ev": h["q1"], "q1_dep": a["q1"], "q2_ev": h["q2"], "q2_dep": a["q2"],
                "q3_ev": h["q3"], "q3_dep": a["q3"], "q4_ev": h["q4"], "q4_dep": a["q4"],
                "uzatma_ev": h["uzatma"], "uzatma_dep": a["uzatma"],
            })
        else:
            h, a = skor(hd), skor(ad)
            r.update({
                "ms_ev": h["ms"], "ms_dep": a["ms"], "iy_ev": h["iy"], "iy_dep": a["iy"],
                "y2_ev": h["y2"], "y2_dep": a["y2"], "nt_ev": h["nt"], "nt_dep": a["nt"],
                "uzatma_ev": h["uzatma"], "uzatma_dep": a["uzatma"],
                "penalti_ev": h["penalti"], "penalti_dep": a["penalti"],
            })
        return r


def maclar(tid, tarih):
    j = cek(f"{API}/unique-tournament/{tid}/scheduled-events/{tarih}")
    if not j:
        return []
    return [mac_parse(e) for e in j.get("events", [])]


# İstatistik anahtarı → bizim alan adı. SofaScore dönemleri ALL / 1ST / 2ND verir,
# yani korner ve kartların DEVRE AYRIMI da elimizde (Betradar'daki her kalem burada var).
STAT_ALAN = {"cornerKicks": "korner", "yellowCards": "sari", "redCards": "kirmizi", "fouls": "faul"}


def mac_detay(eid):
    """Tek maçın korner/kart/faul sayıları + gol & kart dökümü.
    2 istek: /event/{id}/statistics + /event/{id}/incidents. Veri yoksa boş sözlük."""
    d = {}
    st = cek(f"{API}/event/{eid}/statistics")
    time.sleep(BEKLE)
    for g in ((st or {}).get("statistics") or []):
        per = (g.get("period") or "").upper()
        onek = "" if per == "ALL" else ("iy_" if per == "1ST" else None)
        if onek is None:
            continue                      # 2ND ayrıca gerekmiyor (tüm maç − ilk yarı)
        dolu = False
        for gr in g.get("groups", []):
            for i in gr.get("statisticsItems", []):
                alan = STAT_ALAN.get(i.get("key"))
                if not alan:
                    continue
                h, a = i.get("homeValue"), i.get("awayValue")
                if h is None or a is None:
                    continue
                d[onek + alan] = [int(h), int(a)]
                dolu = True
        # SofaScore SIFIR olan kart kalemini HİÇ göndermiyor: kırmızı kart yoksa `redCards`
        # anahtarı yok. Eksik bırakılırsa kirmizi_* NULL kalıyor ve kart_ok hiç 1 olmuyordu.
        # Dönem bloğu doluysa (korner/faul geldiyse) eksik kart kalemi = 0 demektir.
        if dolu:
            for alan in ("sari", "kirmizi"):
                d.setdefault(onek + alan, [0, 0])

    inc = cek(f"{API}/event/{eid}/incidents")
    time.sleep(BEKLE)
    if inc is not None:
        d["olay_ok"] = True               # olay dökümü GELDİ (gol yoksa bile liste kesin)
    goller, kartlar, pen = [], [], [0, 0]
    for i in ((inc or {}).get("incidents") or []):
        t = i.get("incidentType")
        ev_mi = bool(i.get("isHome"))
        dk = i.get("time")
        oyuncu = ((i.get("player") or {}).get("name")) or ""
        if t == "goal":
            sinif = i.get("incidentClass") or "regular"
            goller.append({"dk": dk, "takim": "ev" if ev_mi else "dep", "oyuncu": oyuncu,
                           "tip": sinif, "skor": f"{i.get('homeScore')}-{i.get('awayScore')}"})
            if sinif == "penalty":
                pen[0 if ev_mi else 1] += 1
        elif t == "card":
            kartlar.append({"dk": dk, "takim": "ev" if ev_mi else "dep", "oyuncu": oyuncu,
                            "tip": i.get("incidentClass") or "yellow"})
    if goller:
        goller.sort(key=lambda x: x["dk"] or 0)
        d["goller"] = goller
        d["penalti_gol"] = pen
    if kartlar:
        kartlar.sort(key=lambda x: x["dk"] or 0)
        d["kartlar"] = kartlar
    return d


def detay_ekle(mac_listesi, havuz):
    """Aday maçlarımıza karşılık gelen BİTMİŞ havuz kayıtlarına detay (korner/kart/faul/gol) ekle.

    Neden yalnız adaylar: havuzda günde 1200+ maç var, hepsine 2 ek istek atmak anlamsız.
    Aday sayısı günde birkaç tane olduğu için maliyet ihmal edilebilir.
    Eşleştirme burada GEVŞEK tutulur (0.70): yanlış kayda detay eklense bile PHP yalnız
    KENDİ eşleştirdiği kaydın detayını kullanır → en kötü ihtimalle veri eksik kalır, yanlış yazılmaz."""
    if not mac_listesi:
        return 0

    def oran(a, b):
        if a == b:
            return 1.0
        if not a or not b:
            return 0.0
        # Sağlayıcılar takım adını KISALTIYOR: bizde "LDU Quito", SofaScore'da sadece "LDU".
        # Salt oran bakınca 0.55 çıkıp eleniyordu; biri diğerinin içinde geçiyorsa kabul et.
        kisa, uzun = (a, b) if len(a) <= len(b) else (b, a)
        if len(kisa) >= 3 and kisa in uzun:
            return 0.95
        return difflib.SequenceMatcher(None, a, b).ratio()

    hedefler = {}
    for satir in mac_listesi:
        p = [x.strip() for x in satir.split("|")]
        if len(p) < 2:
            continue
        ev, dep = p[0], p[1]
        ts = int(p[2]) if len(p) > 2 and p[2].isdigit() else None
        en, dn = _takim_norm(ev), _takim_norm(dep)
        for m in havuz:
            if m.get("durum") != "finished" or m.get("id") in hedefler:
                continue
            e2, d2 = oran(en, _takim_norm(m.get("ev"))), oran(dn, _takim_norm(m.get("dep")))
            if e2 >= 0.70 and d2 >= 0.70:
                hedefler[m.get("id")] = m
                continue
            # TEK TARAF + AYNI SAAT: bir takım aynı anda iki maç oynayamaz, diğer taraf
            # kısaltma olabilir ("Vaasan Palloseura" ↔ "VPS"). PHP'deki lig teyidinin karşılığı.
            if ts and m.get("ts") and abs(m["ts"] - ts) <= 20 * 60 and max(e2, d2) >= 0.85:
                hedefler[m.get("id")] = m
    for i, (eid, m) in enumerate(hedefler.items(), 1):
        ilerleme_yaz(asama="detay", mesaj=f"Maç detayı (korner/kart) — {m.get('ev')} - {m.get('dep')} ({i}/{len(hedefler)})")
        d = mac_detay(eid)
        if d:
            m["detay"] = d
    return len(hedefler)


def main():
    if len(sys.argv) < 2:
        print(json.dumps({"ok": False, "hata": "tarih gerekli"}))
        return
    # Windows konsolu Türkçe cp1254 → Lehçe/Çekçe harf (ę, ř…) içeren çıktıda print çöküyordu
    # ve çökme `ilerleme_yaz("bitti")` satırından ÖNCE olduğu için panel sonsuza kadar
    # "maçlar çekiliyor" durumunda asılı kalıyordu. Çıktıyı UTF-8'e sabitle.
    try:
        sys.stdout.reconfigure(encoding="utf-8", errors="replace")
    except Exception:
        pass
    tarih = sys.argv[1]
    tz = "10800"
    global ILERLEME_DOSYA, SPOR
    if "--tz" in sys.argv:
        tz = sys.argv[sys.argv.index("--tz") + 1]
    if "--ilerleme" in sys.argv:
        ILERLEME_DOSYA = sys.argv[sys.argv.index("--ilerleme") + 1]
    if "--spor" in sys.argv:
        s = sys.argv[sys.argv.index("--spor") + 1].strip().lower()
        if s in ("football", "basketball"):
            SPOR = s

    ulke_flag = None
    ulke_ad = []
    # Ülke listesi DOSYADAN okunur (tercih edilen yol). Argümanla geçmek Windows'ta bozuluyordu:
    # PowerShell Start-Process -ArgumentList boşluklu değeri tırnaklamıyor, "International Clubs"
    # ikiye bölünüp Python'a yalnız "…,International" ulaşıyor, "Clubs" başıboş argüman oluyordu.
    # Sonuç: CONMEBOL Libertadores gibi ligler hiç taranmıyordu. Dosya bu sorundan bağımsız.
    if "--ulke-dosya" in sys.argv:
        try:
            with open(sys.argv[sys.argv.index("--ulke-dosya") + 1], encoding="utf-8") as f:
                ulke_ad = [x.strip() for x in f.read().split(",") if x.strip()]
        except Exception:
            ulke_ad = []
    elif "--ulke-adlari" in sys.argv:     # elle çalıştırma için korundu
        ulke_ad = [x.strip() for x in sys.argv[sys.argv.index("--ulke-adlari") + 1].split(",") if x.strip()]
    # Aday maç listesi ("Ev|Deplasman" satırları) — günlük dizinde olmayan maçları
    # takım ucundan telafi etmek için (bkz. eksik_maclari_ekle).
    lig_listesi = []
    for bayrak in ("--mac-dosya", "--lig-dosya"):          # --lig-dosya eski ad, uyumluluk
        if bayrak in sys.argv:
            try:
                with open(sys.argv[sys.argv.index(bayrak) + 1], encoding="utf-8") as f:
                    lig_listesi = [x.strip() for x in f.read().splitlines() if x.strip()]
            except Exception:
                lig_listesi = []
            break

    ulke_norm = set()
    if ulke_ad:
        ulke_flag = flags_from_names(ulke_ad) or None
        # Ad süzgeci: kategori ucunda olmayan ülkeler (basketbolda Paraguay/Peru/Ekvador) için ŞART.
        # Kıta etiketlerimizin karşılıkları da ada göre eklenir ("International" → "World" vb).
        ulke_norm = _ulke_normset(ulke_ad)
        for a in list(ulke_norm):
            for k in COK_KATEGORI.get(a, ()):
                ulke_norm.add(_norm(k))

    t0 = time.time()
    ilerleme_yaz(asama="basladi", mesaj="Başlıyor…", yuzde=0)
    tur, sayfa = turnuvalar(tarih, tz, ulke_flag, ulke_norm)

    hepsi = []
    toplam = len(tur)
    for i, tid in enumerate(tur, 1):
        ilerleme_yaz(asama="maclar", turnuva_toplam=toplam, turnuva_islenen=i, mac=len(hepsi),
                     yuzde=round(i / toplam * 100), mesaj=f"Maçlar çekiliyor — lig {i}/{toplam} · {len(hepsi)} maç")
        hepsi.extend(maclar(tid, tarih))
        time.sleep(BEKLE)

    # SofaScore'un günlük turnuva dizini eksik → havuzda çıkmayan liglerimizi doğrudan çek.
    # DİZİN BOŞ DÖNSE DE çalışmalı: tek ülke istendiğinde (ör. yalnız "Uruguay") o ülkenin
    # ligleri dizinde hiç yoksa `tur` boş kalıyor; eskiden burada erken çıkılıyordu ve
    # arama yoluyla bulunabilecek ligler de kaçıyordu.
    ek = eksik_maclari_ekle(lig_listesi, hepsi, tarih)
    if ek:
        var_id = {m.get("id") for m in hepsi}
        hepsi.extend([m for m in ek if m.get("id") not in var_id])

    # Aday maçların korner/kart/faul + gol dökümü (yalnız --detay ile; maç başına 2 ek istek)
    detayli = 0
    if "--detay" in sys.argv:
        detayli = detay_ekle(lig_listesi, hepsi)

    if not tur and not hepsi:
        msj = "Turnuva listesi alınamadı — 403/ağ hatası (proxy?) ya da bu ülkelerde o gün maç yok"
        ilerleme_yaz(asama="hata", yuzde=0, mesaj=msj)
        print(json.dumps({"ok": False, "hata": msj, "tarih": tarih}, ensure_ascii=False))
        return

    hepsi.sort(key=lambda x: x["ts"] or 0)
    sonuc = {
        "ok": True, "spor": SPOR, "tarih": tarih, "tz": tz, "sayfa": sayfa,
        "turnuva_sayisi": len(tur), "mac_sayisi": len(hepsi), "sure_sn": round(time.time() - t0, 1),
        "ulke_filtre": ulke_ad or None, "proxy_sayisi": len(PROXYLER),
        # Maliyet ölçümü: istek sayısı MAÇ başına değil TURNUVA başınadır (bkz. akış).
        "istek": dict(ISTEK), "mac_basina_istek": round(ISTEK["cagri"] / max(len(hepsi), 1), 3),
        "detayli_mac": detayli,
        "proxy_istatistik": [{"adres": k.split("@")[-1], **v} for k, v in ISTATISTIK.items()],
        "maclar": hepsi,
    }
    metin = json.dumps(sonuc, ensure_ascii=False)
    if "--cikti" in sys.argv:
        with open(sys.argv[sys.argv.index("--cikti") + 1], "w", encoding="utf-8") as f:
            f.write(metin)
    else:
        print(metin)
    ilerleme_yaz(asama="bitti", yuzde=100, mac=len(hepsi), turnuva=len(tur), sure=sonuc["sure_sn"],
                 mesaj=f"Bitti — {len(hepsi)} maç, {len(tur)} lig ({sonuc['sure_sn']} sn)")


if __name__ == "__main__":
    main()
