"""
Stažení detailu receptů (NacistPredpis) z eRecept SÚKL.

Logika přeskakování:
  - Recept je v recept_doklad se stav_terminal = 1  →  přeskočit (vydaný / zrušený)
  - Recept není v recept_doklad                     →  stáhnout (nový)
  - Recept je v recept_doklad se stav_terminal = 0  →  stáhnout znovu (dosud nevyzvednutý)

Spuštění:
    python 10_StahnoutXML.py              # všechny od 2025-01-01
    python 10_StahnoutXML.py --od 2026-01-01
    python 10_StahnoutXML.py --limit 50   # testování

XML odpovědi se ukládají do xml_archive/YYYY-MM-DD/ERP_KOD.xml
"""

import sys
import time
import uuid
from datetime import datetime, timezone, date
from pathlib import Path

import random
import fdb
import pymysql
import pymysql.cursors
from requests import Session
from requests_pkcs12 import Pkcs12Adapter

if hasattr(sys.stdout, "reconfigure"):
    sys.stdout.reconfigure(errors="replace")

# ── Konfigurace eRecept ──────────────────────────────────────────────────────
PFX_FILE   = Path(__file__).parent.parent / "AMBSUKL214235369G_31DEC2024.pfx"
PFX_PASS   = "Vlado7309208104++"
API_USER   = "e08c89c6-2b1a-4eba-8ed9-4e3e63618379"
API_PASS   = "Buzalka@Vladimir2025"
UZIVATEL   = "E08C89C6-2B1A-4EBA-8ED9-4E3E63618379"
PRACOVISTE = "00214235367"
ENDPOINT   = "https://lekar-soap.erecept.sukl.cz/cuer/Lekar"
NAMESPACE  = "http://www.sukl.cz/erp/201704"

PAUZA_MIN = 4   # sekund mezi voláními API (minimum)
PAUZA_MAX = 6   # sekund mezi voláními API (maximum)

# ── Konfigurace Firebird ─────────────────────────────────────────────────────
FB_DSN     = r'localhost:c:\medicus 3\data\medicus.fdb'
FB_USER    = 'SYSDBA'
FB_PASS    = 'masterkey'
FB_CHARSET = 'win1250'

# ── Konfigurace MySQL ────────────────────────────────────────────────────────
DB = dict(
    host        = "192.168.1.76",
    user        = "root",
    password    = "Vlado9674+",
    database    = "medicus",
    charset     = "utf8mb4",
    cursorclass = pymysql.cursors.DictCursor,
)

# ── Adresáře ─────────────────────────────────────────────────────────────────
XML_DIR = Path(__file__).parent / "xml_archive"

# ── Parametry spuštění (uprav zde) ───────────────────────────────────────────
DATUM_OD = "2025-01-01"   # recepty od tohoto data
LIMIT    = None             # max počet receptů ke stažení; None = bez omezení


# ─────────────────────────────────────────────────────────────────────────────

def nacti_terminal_set(mysql_conn):
    """
    Vrátí set ERP kódů, které jsou již terminální (vydané / zrušené / expirované).
    Jeden dotaz na začátku — pak jen O(1) lookup v Pythonu.
    """
    with mysql_conn.cursor() as cur:
        cur.execute("SELECT id_dokladu FROM recept_doklad WHERE stav_terminal = 1")
        return {row["id_dokladu"] for row in cur.fetchall()}


def nacti_erp_kody(fb_conn, datum_od, limit=None):
    """
    Načte unikátní ERP kódy z Firebirdu (recept_epodani.erp) od datum_od.
    Vrací list tuplů: (datum, lek, dop, idpac, prijmeni, jmeno, erp_kod)
    """
    if limit:
        sql = f"SELECT FIRST {int(limit)}"
    else:
        sql = "SELECT"

    sql += """
        r.datum, r.lek, r.dop, r.idpac,
        TRIM(kar.prijmeni) AS prijmeni, TRIM(kar.jmeno) AS jmeno,
        ep.erp
        FROM recept r
        JOIN recept_epodani ep ON r.id_epodani = ep.id
        JOIN kar ON r.idpac = kar.idpac
        WHERE r.datum >= ? AND ep.erp IS NOT NULL
        ORDER BY r.datum DESC
    """

    cur = fb_conn.cursor()
    cur.execute(sql, [datum_od])
    rows = cur.fetchall()
    cur.close()

    # deduplikace dle ERP kódu — jeden recept může mít více léků (řádků)
    seen = set()
    unique = []
    for row in rows:
        erp = row[6]
        if erp not in seen:
            seen.add(erp)
            unique.append(row)
    return unique


def volej_nacist_predpis(sess, erp_kod):
    """Zavolá NacistPredpis SOAP a vrátí (status_code, response_text)."""
    id_zpravy = str(uuid.uuid4())
    odeslano  = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S+00:00")

    soap_body = (
        '<?xml version="1.0" encoding="UTF-8"?>'
        '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
        '<soapenv:Body>'
        f'<NacteniPredpisuDotaz xmlns="{NAMESPACE}">'
        f'<Doklad>'
        f'<Pristupujici>'
        f'<Uzivatel>{UZIVATEL}</Uzivatel>'
        f'<Pracoviste>{PRACOVISTE}</Pracoviste>'
        f'</Pristupujici>'
        f'<Identifikator>'
        f'<ID_Dokladu>{erp_kod}</ID_Dokladu>'
        f'</Identifikator>'
        f'</Doklad>'
        f'<Zprava>'
        f'<ID_Zpravy>{id_zpravy}</ID_Zpravy>'
        f'<Verze>202501A</Verze>'
        f'<Odeslano>{odeslano}</Odeslano>'
        f'<SW_Klienta>MEDICUS_____</SW_Klienta>'
        f'</Zprava>'
        f'</NacteniPredpisuDotaz>'
        '</soapenv:Body>'
        '</soapenv:Envelope>'
    )

    headers = {
        "Content-Type": 'text/xml; charset="UTF-8"',
        "SOAPAction":   '"NacistPredpis"',
        "User-Agent":   "Medicus",
    }

    resp = sess.post(ENDPOINT, data=soap_body.encode("utf-8"), headers=headers, timeout=15)
    return resp.status_code, resp.text


def main():
    datum_od = DATUM_OD
    limit    = LIMIT

    dnes    = date.today().isoformat()
    out_dir = XML_DIR / dnes
    out_dir.mkdir(parents=True, exist_ok=True)

    # ── 1. Načti terminální sadu z MySQL ─────────────────────────────────────
    print("Připojuji MySQL...")
    mysql = pymysql.connect(**DB)
    terminal = nacti_terminal_set(mysql)
    mysql.close()
    print(f"  Terminálních receptů v DB: {len(terminal)}\n")

    # ── 2. Načti ERP kódy z Firebirdu ────────────────────────────────────────
    print("Připojuji Firebird...")
    fb   = fdb.connect(dsn=FB_DSN, user=FB_USER, password=FB_PASS, charset=FB_CHARSET)
    rows = nacti_erp_kody(fb, datum_od, limit)
    fb.close()
    print(f"  Unikátních ERP kódů v Medicusu (od {datum_od}): {len(rows)}\n")

    if not rows:
        print("Žádné recepty k zpracování.")
        return

    # ── 3. Filtruj — přeskoč terminální ──────────────────────────────────────
    ke_stazeni  = [r for r in rows if r[6] not in terminal]
    preskoceno  = len(rows) - len(ke_stazeni)
    print(f"  Přeskočeno (terminální): {preskoceno}")
    print(f"  Ke stažení:              {len(ke_stazeni)}\n")

    if not ke_stazeni:
        print("Vše je již staženo a terminální. Hotovo.")
        return

    # ── 4. SOAP session ───────────────────────────────────────────────────────
    sess = Session()
    sess.mount("https://", Pkcs12Adapter(pkcs12_filename=PFX_FILE, pkcs12_password=PFX_PASS))
    sess.auth = (API_USER, API_PASS)

    ok    = 0
    chyby = 0

    for i, row in enumerate(ke_stazeni, 1):
        datum_rec, lek, dop, idpac, prijmeni, jmeno, erp_kod = row
        lek_str = f"{lek} {dop}".strip() if dop else str(lek or "").strip()
        label   = f"{prijmeni} {jmeno}".strip()

        print(f"[{i:4d}/{len(ke_stazeni)}] {label:30s} {erp_kod}  ", end="", flush=True)

        try:
            status, text = volej_nacist_predpis(sess, erp_kod)

            je_chyba = status != 200 or "<soap:Fault" in text or "Fault>" in text

            if not je_chyba:
                xml_file = out_dir / f"{erp_kod}.xml"
                xml_file.write_text(text, encoding="utf-8")
                print(f"OK  {len(text.encode()) / 1024:5.1f} KB  {lek_str[:40]}")
                ok += 1
            else:
                chyba_short = text[:120].replace("\n", " ")
                print(f"CHYBA  HTTP {status}  {chyba_short}")
                xml_file = out_dir / f"{erp_kod}_CHYBA.xml"
                xml_file.write_text(text, encoding="utf-8")
                chyby += 1

        except Exception as e:
            print(f"EXCEPTION  {e}")
            chyby += 1

        if i < len(ke_stazeni):
            time.sleep(random.uniform(PAUZA_MIN, PAUZA_MAX))

    print(f"\nHotovo: {ok} OK, {chyby} chyb, {preskoceno} přeskočeno")
    print(f"XML: {out_dir}")


if __name__ == "__main__":
    main()
