"""funkce_ext.py – zápis PDF souborů přímo do měsíční externí Firebird DB
místo do hlavní medicus.fdb – spouštět na Windows

Náhrada za funkce.zapis_file() v s03soubory.py.
Binární data souboru se uloží do MEDICUS_FILES_YYYYMM.fdb (DATA tabulka),
do hlavní FILES.BODY se vloží 48bajtová reference.

Formát FILES.BODY reference (48 B):
  magic    4 B  = b'\\xee\\xbb\\xaa\\x0b'
  uid     32 B  = UUID4 hex (ASCII, 32 znaků)
  dblen    4 B  = délka DBNAME jako little-endian uint32
  dbname   N B  = DBNAME ASCII (např. 'DB202603', 8 B)
"""

import os
import struct
import uuid
import fdb


# Magic bajty identifikující referenci na externí DB
MAGIC = b'\xee\xbb\xaa\x0b'


# ─── Pomocné funkce ──────────────────────────────────────────────────────────

def make_body_ref(uid: str, dbname: str) -> bytes:
    """Sestaví 48bajtovou binární referenci pro FILES.BODY."""
    uid_bytes = uid.encode('ascii')       # 32 B
    dbname_bytes = dbname.encode('ascii')  # typicky 8 B ('DB202603')
    return MAGIC + uid_bytes + struct.pack('<I', len(dbname_bytes)) + dbname_bytes


def _get_ext_server(vstupconnection):
    """Zjistí SERVER z existující EXTERNI_DB (např. 'localhost/3053')."""
    cur = vstupconnection.cursor()
    cur.execute(
        "SELECT SERVER FROM EXTERNI_DB WHERE DBNAME LIKE 'DB%' ORDER BY DBNAME DESC ROWS 1"
    )
    row = cur.fetchone()
    return row[0] if row else 'localhost/3053'


def _get_ext_heslo(vstupconnection):
    """Přečte šifrované heslo z existující EXTERNI_DB.
    Všechny externí DB mají stejné heslo (masterkey, jen zašifrované Medicusem),
    takže stačí vzít heslo z libovolné existující položky."""
    cur = vstupconnection.cursor()
    cur.execute(
        "SELECT HESLO FROM EXTERNI_DB WHERE DBNAME LIKE 'DB%' ORDER BY DBNAME DESC ROWS 1"
    )
    row = cur.fetchone()
    return row[0] if row else 'masterkey'


def _vytvor_externi_db(ext_path):
    """Vytvoří novou prázdnou externí Firebird DB s tabulkou DATA a generátorem GEN_UID.
    Schéma odpovídá tomu, co vytváří Medicus sám při prvním exportu daného měsíce."""
    print(f"  Vytvářím novou ext DB: {ext_path}")
    conn = fdb.create_database(
        dsn=f'localhost:{ext_path}',
        user='SYSDBA',
        password='masterkey',
        charset='WIN1250',
        page_size=16384
    )
    cur = conn.cursor()
    cur.execute("""
        CREATE TABLE DATA (
            UID      VARCHAR(32) NOT NULL,
            DATA     BLOB SUB_TYPE 0,
            DATASIZE INTEGER,
            CHUNK    INTEGER
        )
    """)
    cur.execute("CREATE GENERATOR GEN_UID")
    conn.commit()
    print(f"  Nová ext DB vytvořena: {ext_path}")
    return conn


# ─── Hlavní funkce ───────────────────────────────────────────────────────────

def zapis_file_ext(vstupconnection, idpac, cesta, souborname, prvnizavorka,
                   soubordate, souborfiledate, poznamka,
                   ext_base_path=r'u:\externi'):
    """Zapíše PDF soubor do měsíční externí DB a vrátí fileid.

    Parametry jsou shodné s funkce.zapis_file() – stačí prohodit import.

    Postup:
      1. Určí měsíc z soubordate → DBNAME (např. 'DB202603')
      2. Načte binární data PDF
      3. Najde nebo vytvoří měsíční MEDICUS_FILES_YYYYMM.fdb
      4. Zapíše data do DATA tabulky pod novým UID (UUID4 hex)
      5. Sestaví 48bajtovou BODY referenci
      6. Získá nové FILES ID z Gen_Files
      7. Vloží záznam do hlavní FILES tabulky (BODY = reference, ne BLOB)
      8. Vrátí fileid (shodné s funkce.zapis_file())
    """
    import funkce  # get_files_id ze stávajícího funkce.py

    # 1. Měsíc a DBNAME
    yyyymm = soubordate.strftime('%Y%m')
    dbname = f'DB{yyyymm}'
    print(f"  DBNAME: {dbname}")

    # 2. Binární data PDF
    soubor_cesta = os.path.join(cesta, souborname)
    with open(soubor_cesta, 'rb') as f:
        data = f.read()
    print(f"  Načten soubor: {souborname} ({len(data):,} B)")

    # 3. Připojení k externí DB
    cur = vstupconnection.cursor()
    cur.execute(
        "SELECT SERVER, PATH FROM EXTERNI_DB WHERE DBNAME = ?", (dbname,)
    )
    row = cur.fetchone()

    if row:
        # Existující měsíční DB – připojíme se
        ext_server_raw, ext_path = row[0], row[1]
        # SERVER je "localhost/3053" (FBScanner proxy) – bereme jen hostname
        ext_server = ext_server_raw.split('/')[0]
        print(f"  Existující ext DB: {dbname} → {ext_path}")
        conn_ext = fdb.connect(
            dsn=f'{ext_server}:{ext_path}',
            user='SYSDBA',
            password='masterkey',
            charset='WIN1250'
        )
    else:
        # Nová měsíční DB – vytvoříme a zaregistrujeme
        ext_filename = f'MEDICUS_FILES_{yyyymm}.fdb'
        ext_path = os.path.join(ext_base_path, ext_filename)
        conn_ext = _vytvor_externi_db(ext_path)

        # Zaregistrovat do EXTERNI_DB (heslo zkopírujeme z existující položky)
        ext_server = _get_ext_server(vstupconnection)
        heslo = _get_ext_heslo(vstupconnection)
        cur.execute(
            "INSERT INTO EXTERNI_DB (DBNAME, SERVER, PATH, HESLO) VALUES (?, ?, ?, ?)",
            (dbname, ext_server, ext_path, heslo)
        )
        vstupconnection.commit()
        print(f"  Registrována v EXTERNI_DB: {dbname}, server={ext_server}")

    # 4. Zápis do DATA tabulky
    uid = uuid.uuid4().hex  # 32 hex znaků, vždy unikátní
    cur_ext = conn_ext.cursor()
    cur_ext.execute(
        "INSERT INTO DATA (UID, DATA, DATASIZE, CHUNK) VALUES (?, ?, ?, ?)",
        (uid, data, len(data), 0)
    )
    conn_ext.commit()
    conn_ext.close()
    print(f"  Zapsáno do ext DB: UID={uid}")

    # 5. BODY reference (48 B)
    body_ref = make_body_ref(uid, dbname)
    print(f"  BODY ref: {body_ref.hex()}")

    # 6. Nové FILES ID
    fileid = funkce.get_files_id(vstupconnection)
    if fileid is None:
        raise RuntimeError("Nepodařilo se získat nové FILES ID (Gen_Files selhal)!")

    # 7. INSERT do hlavní FILES tabulky
    cur.execute(
        "INSERT INTO FILES "
        "(id, iduzi, iddoctyp, typ, idpac, filename, body, datum, datsouboru, poznamka) "
        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
        (fileid, 6, 1, 1, idpac,
         prvnizavorka + '.pdf',
         body_ref,
         soubordate, souborfiledate,
         poznamka[:99])
    )
    vstupconnection.commit()
    print(f"  FILES záznam vytvořen: ID={fileid}, idpac={idpac}, "
          f"soubor={prvnizavorka}.pdf")

    return fileid
