# -*- coding: utf-8 -*-
"""
JV-Link 単体診断: 指定期間に欲しい情報があるかだけを見る。

  - レース情報 (RA) があるか
  - 成績確定 (RA DataKubun=7) があるか
  - 確定オッズ (O1) があるか
  - O1 の中身に単勝オッズ値があるか  <-- これが本丸

keiba.db は見ない。JV-Link に揃っていればデータ取得は可能、という前提。

編集: FROM_TO / OPTION のみ
実行: venv32\\Scripts\\python.exe diag_jvlink.py
"""
from __future__ import annotations

import platform
import sys
import time
from collections import Counter

FROM_TO = "20260101000000-20260201000000"
DATASPEC = "RACE"
OPTION = 4
BUFSIZE = 300000
PROGIDS = ("JVDTLab.JVLink", "JVDTLabLib.JVLink")


def _parse_range(from_to: str) -> tuple[str, str, str, str]:
    s = from_to.strip()
    if "-" in s:
        a, b = s.split("-", 1)
        if len(a) >= 8 and len(b) >= 8:
            y = a[:4]
            label = f"{y}-{a[4:6]}-{a[6:8]} .. {b[:4]}-{b[4:6]}-{b[6:8]}"
            return label, y, a[4:8], b[4:8]
    y = s[:4] if len(s) >= 4 else "????"
    md = s[4:8] if len(s) >= 8 else "0101"
    return s, y, md, md


def _race_key(raw: str) -> str | None:
    if len(raw) < 27:
        return None
    return raw[11:15] + raw[19:21] + raw[15:19] + raw[25:27]


def _in_range(raw: str, year: str, md_from: str, md_to: str) -> bool:
    if len(raw) < 19:
        return False
    return raw[11:15] == year and md_from <= raw[15:19] <= md_to


def _o1_has_tanodds(raw: str) -> bool:
    hdr, bpc = 43, 8
    if len(raw) < hdr + bpc:
        return False
    data = raw[hdr:]
    for i in range(0, len(data) - bpc + 1, bpc):
        odds_s = data[i + 2 : i + 6].strip()
        if odds_s and odds_s.strip("0"):
            try:
                if int(odds_s) > 0:
                    return True
            except ValueError:
                pass
    return False


def main() -> None:
    arch = platform.architecture()[0]
    label, year, md_from, md_to = _parse_range(FROM_TO)

    print("=== JV-Link 単体診断（keiba.db は見ない） ===")
    print(f"Python {sys.version.split()[0]} ({arch})")
    print(f"期間: {label}")
    print(f"FROM_TO={FROM_TO}  OPTION={OPTION}")
    print("")
    print("見るもの:")
    print("  RA      = レース情報がある")
    print("  RA k7   = 成績確定")
    print("  O1      = 確定オッズレコードがある")
    print("  O1+odds = 単勝オッズの数値が入っている  <- 欲しい情報")
    print("")

    if arch != "32bit":
        print("ERROR: venv32\\Scripts\\python.exe を使う")
        return

    import win32com.client as win32

    jv = None
    for progid in PROGIDS:
        try:
            jv = win32.Dispatch(progid)
            print(f"COM ProgID: {progid}")
            break
        except Exception as e:
            print(f"ProgID {progid} NG: {e}")
    if jv is None:
        print("ERROR: JV-Link COM を開けません")
        return

    rc = jv.JVInit("UNKNOWN")
    print(f"JVInit rc={rc}")
    if rc != 0:
        return

    r = jv.JVOpen(DATASPEC, FROM_TO, OPTION, 0, 0, "")
    rc, readcount, dlcount, lastts = r[0], r[1], r[2], r[3]
    print(f"JVOpen rc={rc} read={readcount} dl={dlcount} lastts={lastts}")
    if rc < 0 or readcount == 0:
        jv.JVClose()
        print("-> データを開けません。FROM_TO / OPTION を変えて再実行")
        return

    while dlcount > 0:
        st = jv.JVStatus()
        if st < 0 or st >= dlcount:
            break
        time.sleep(1)

    ra_all: set[str] = set()
    ra_k7: set[str] = set()
    o1_all: set[str] = set()
    o1_odds: set[str] = set()
    types: Counter[str] = Counter()

    while True:
        r = jv.JVRead(" " * BUFSIZE, BUFSIZE, "")
        rc, data = r[0], r[1]
        if rc == 0:
            break
        if rc in (-1, -3):
            if rc == -3:
                time.sleep(1)
            continue
        if rc < 0:
            print(f"JVRead error rc={rc}")
            break
        if len(data) < 2:
            continue
        types[data[:2]] += 1
        if not _in_range(data, year, md_from, md_to):
            continue
        rk = _race_key(data)
        if not rk:
            continue
        kind, kubun = data[:2], data[2:3]
        if kind == "RA":
            ra_all.add(rk)
            if kubun == "7":
                ra_k7.add(rk)
        elif kind == "O1":
            o1_all.add(rk)
            if _o1_has_tanodds(data):
                o1_odds.add(rk)

    jv.JVClose()

    print("")
    print(f"=== 結果（{label}・レース数） ===")
    print(f"  RA           {len(ra_all)}")
    print(f"  RA k7        {len(ra_k7)}")
    print(f"  O1           {len(o1_all)}")
    print(f"  O1+odds      {len(o1_odds)}")
    print("")
    print(f"ストリーム全体の件数(参考): {dict(sorted(types.items()))}")

    k7, odds = len(ra_k7), len(o1_odds)
    print("")
    print("=== 判定 ===")
    if k7 == 0:
        print("成績確定レースが無い。期間か FROM_TO を見直す。")
    elif odds >= k7 * 0.9:
        print(f"OK: 成績確定 {k7} レースのうちオッズ付き {odds}。")
        print("-> JV-Link に欲しい情報がある。この期間は取得可能。")
    elif odds > 0:
        pct = 100 * odds // k7 if k7 else 0
        print(f"一部のみ: 成績確定 {k7} に対しオッズ付き {odds} ({pct}%)。")
        print("-> JV-Link 時点でオッズが欠けている。jrvltsql を直しても増えない可能性大。")
        print("-> JRA-VAN 仕様・契約・DataKubun の確認が必要。")
        missing = list(ra_k7 - o1_odds)[:1]
        if missing:
            print(f"   例(オッズ無し): race_key={missing[0]}")
    else:
        print(f"NG: 成績確定 {k7} あるが O1+odds=0。")
        print("-> JV-Link から確定単勝オッズが取れていない。")


if __name__ == "__main__":
    main()
