#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Najde přesné datum změny stavu pojištění pomocí binary search.
Používá existující VZP B2B klient + ukládá výsledky do MySQL.

Cíl:
- minimalizovat počet dotazů na VZP
- přesně určit první den, kdy stav != '1'
"""

import sys
import time
import logging
from pathlib import Path
from datetime import date, timedelta
import pymysql

# ==========================================
# PROJECT ROOT (import fix)
# ==========================================
PROJECT_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(PROJECT_ROOT))

from knihovny.medicus_db import MedicusDB
from knihovny.vzpb2b_client import VZPB2BClient

# ==========================================
# LOGGING
# ==========================================
logging.basicConfig(
    filename="insurance_binary_search.log",
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    encoding="utf-8"
)

console = logging.getLogger("console")
console.setLevel(logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("%(message)s"))
console.addHandler(handler)

def log(msg):
    logging.info(msg)
    console.info(msg)

# ==========================================
# MYSQL
# ==========================================
mysql = pymysql.connect(
    host="192.168.1.76",
    port=3307,
    user="root",
    password="Vlado9674+",
    database="medevio",
    charset="utf8mb4",
    autocommit=True,
    cursorclass=pymysql.cursors.DictCursor
)

# ==========================================
# SAVE RESULT
# ==========================================
def save_insurance_status(mysql_conn, rc, prijmeni, jmeno, k_datu, result, xml):
    sql = """
    INSERT INTO vzp_stav_pojisteni
        (rc, prijmeni, jmeno, k_datu,
         stav, kod_pojistovny, nazev_pojistovny,
         pojisteni_kod, stav_vyrizeni, response_xml)
    VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
    """
    with mysql_conn.cursor() as cur:
        cur.execute(sql, (
            rc,
            prijmeni,
            jmeno,
            k_datu,
            result["stav"],
            result["kodPojistovny"],
            result["nazevPojistovny"],
            result["pojisteniKod"],
            result["stavVyrizeni"],
            xml
        ))

# ==========================================
# VZP CONFIG
# ==========================================
HOST = "192.168.1.4"
DB_PATH = r"z:\Medicus 3\data\MEDICUS.FDB"

PFX_PATH = PROJECT_ROOT / "certificates" / "MBcert.pfx"
PFX_PASSWORD = "Vlado7309208104++"

ENV = "prod"
ICZ = "00000000"
DIC = "00000000"

# ==========================================
# INIT
# ==========================================
db = MedicusDB(HOST, DB_PATH)
vzp = VZPB2BClient(
    ENV,
    str(PFX_PATH),
    PFX_PASSWORD,
    icz=ICZ,
    dic=DIC
)

# ==========================================
# HELPER FUNCTIONS
# ==========================================
def vzp_query(rc, prijmeni, jmeno, d):
    xml = vzp.stav_pojisteni(rc=rc, k_datu=d.isoformat())
    result = vzp.parse_stav_pojisteni(xml)
    save_insurance_status(mysql, rc, prijmeni, jmeno, d, result, xml)
    time.sleep(2)  # VZP rate limit
    return result["stav"]

def binary_search_change(rc, prijmeni, jmeno, start_date, end_date):
    """
    Najde PRVNÍ den, kdy stav != '1'
    """
    low = start_date
    high = end_date
    found = None

    while low <= high:
        mid = low + (high - low) // 2
        log(f"   🔍 {rc} probing {mid}")

        stav = vzp_query(rc, prijmeni, jmeno, mid)

        if stav == '1':
            low = mid + timedelta(days=1)
        else:
            found = mid
            high = mid - timedelta(days=1)

    return found

# ==========================================
# LOAD CANDIDATES
# ==========================================
with mysql.cursor() as cur:
    cur.execute("""
        SELECT
    x.rc,
    p.prijmeni,
    p.jmeno,
    x.last_ok
FROM (
    SELECT
        rc,
        MAX(CASE WHEN stav = '1' THEN k_datu END) AS last_ok,
        MAX(k_datu) AS last_seen
    FROM vzp_stav_pojisteni
    GROUP BY rc
) x
JOIN vzp_stav_pojisteni p
  ON p.rc = x.rc
 AND p.k_datu = x.last_seen
WHERE
    x.last_ok IS NOT NULL
  AND x.last_seen = (
        SELECT MAX(k_datu)
        FROM vzp_stav_pojisteni z
        WHERE z.rc = x.rc AND z.stav <> '1'
    );

    """)
    patients = cur.fetchall()

log(f"Loaded {len(patients)} patients for binary search\n")

# ==========================================
# MAIN LOOP
# ==========================================
today = date.today()

for p in patients:
    rc = p["rc"]
    prijmeni = p["prijmeni"]
    jmeno = p["jmeno"]
    last_ok = p["last_ok"]

    log(f"\n📌 {prijmeni} {jmeno} ({rc}) – searching change")

    change_date = binary_search_change(
        rc,
        prijmeni,
        jmeno,
        last_ok,
        today
    )

    if change_date:
        log(f"   ✅ změna nastala: {change_date}")
    else:
        log("   ⚠️ změna nenalezena")

# ==========================================
# CLEANUP
# ==========================================
db.close()
mysql.close()

log("\nDONE – binary search insurance check finished.")
