"""
03 - Rozdílové stažení nových zpráv z VZP Point schránky
Jde od nejnovější zprávy dolů. Jakmile narazí na zprávu, kterou už máme
stažnou (cílový soubor existuje), ukončí se. Pokud projde celou aktuálně
načtenou stránku bez nálezu existující zprávy, dolazy-loaduje další.
Použití: python 03_stahuj_nove.py
"""

import json
import os
import re
import sys
import time
import winreg
from datetime import datetime
from pathlib import Path

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", ".."))
from Knihovny.najdi_dropbox import get_dropbox_root

INBOX_URL      = "https://point.vzp.cz/Inbox/Message"
CHROME_PROFILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "chrome_profile"))
COOKIES_FILE   = os.path.abspath(os.path.join(os.path.dirname(__file__), "vzp_cookies.json"))
DOWNLOAD_DIR   = os.path.join(get_dropbox_root(), "Ordinace", "Dokumentace_ke_zpracování", "Zúčtovací zprávy", "111 VZP")


def load_cookies(context) -> int:
    if not os.path.exists(COOKIES_FILE):
        return 0
    try:
        with open(COOKIES_FILE, "r", encoding="utf-8") as f:
            cookies = json.load(f)
        context.add_cookies(cookies)
        return len(cookies)
    except Exception:
        return 0


def save_cookies(context) -> int:
    try:
        all_cookies = context.cookies()
        vzp = [c for c in all_cookies if "vzp.cz" in c.get("domain", "")]
        with open(COOKIES_FILE, "w", encoding="utf-8") as f:
            json.dump(vzp, f, indent=2, ensure_ascii=False)
        return len(vzp)
    except Exception:
        return 0


def _delete_chrome_cert_policy() -> None:
    key_path = r"SOFTWARE\Policies\Google\Chrome\AutoSelectCertificateForUrls"
    try:
        key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, access=winreg.KEY_SET_VALUE)
        winreg.DeleteValue(key, "1")
        winreg.CloseKey(key)
    except Exception:
        pass


def parse_date(date_str: str) -> str:
    try:
        dt = datetime.strptime(date_str.strip(), "%d. %m. %Y %H:%M")
        return dt.strftime("%Y-%m-%d")
    except Exception:
        return "0000-00-00"


def safe_filename(name: str) -> str:
    return re.sub(r'[\\/:*?"<>|]', "_", name).strip()


def build_filename(date_str: str, category: str, title: str, original: str) -> str:
    orig_path = Path(original)
    stem = orig_path.stem
    ext  = orig_path.suffix
    name = f"{parse_date(date_str)} {safe_filename(category)} {safe_filename(title)} ({safe_filename(stem)}){ext}"
    if len(name) > 240:
        name = name[:230] + f"({safe_filename(stem)}){ext}"
    return name


def click_load_more(page) -> bool:
    """Jedno kliknutí na 'Načíst další záznamy'. Vrací True pokud přibyly zprávy."""
    before = page.evaluate("document.querySelectorAll('.InboxMessage').length")
    clicked = page.evaluate("""() => {
        const btn = Array.from(document.querySelectorAll('a')).find(a => a.innerText.includes('Načíst další'));
        if (btn) { btn.scrollIntoView(); btn.click(); return true; }
        return false;
    }""")
    if not clicked:
        return False
    try:
        page.wait_for_function(
            f"document.querySelectorAll('.InboxMessage').length > {before}",
            timeout=15_000,
        )
    except Exception:
        return False
    after = page.evaluate("document.querySelectorAll('.InboxMessage').length")
    print(f"  Načteno dalších: {after - before} (celkem {after})")
    time.sleep(0.3)
    return True


def collect_messages(page) -> list[dict]:
    data = page.evaluate("""() => {
        const results = [];
        for (const msg of document.querySelectorAll('.InboxMessage')) {
            const typeIcon = msg.querySelector('.InboxMessage-row--type i[title]');
            const category = typeIcon ? typeIcon.title.trim() : '';
            const titleEl = msg.querySelector('h3.InboxMessage-title');
            const title = titleEl ? titleEl.title.trim() : '';
            const linkEl = msg.querySelector('a.InboxMessage-title-link');
            const linkTitle = linkEl ? linkEl.title.trim() : '';
            const original = linkTitle.split(/\\s+/).pop();
            let date = '';
            for (const row of msg.querySelectorAll('.InboxMessage-row')) {
                if (row.className.trim() === 'InboxMessage-row') {
                    date = row.innerText.trim();
                    break;
                }
            }
            results.push({ title, category, date, original });
        }
        return results;
    }""")

    inbox_msgs = page.locator(".InboxMessage").all()
    messages = []
    for i, item in enumerate(data):
        if i < len(inbox_msgs):
            msg_el = inbox_msgs[i]
            dl = msg_el.locator(".InboxMessage-row--download .i-l")
            if dl.count() > 0:
                item["link_locator"] = dl
                item["link_type"] = "download"
            else:
                zobrazit = msg_el.locator(".InboxMessage-row--download .i-r-1")
                item["link_locator"] = zobrazit if zobrazit.count() > 0 else None
                item["link_type"] = "zobrazit" if zobrazit.count() > 0 else None
                item["msg_locator"] = msg_el
        else:
            item["link_locator"] = None
            item["link_type"] = None
        messages.append(item)

    return messages


def download_message(page, msg: dict, already: set) -> int:
    """Stáhne zprávu. Vrací počet stažených souborů (0 pokud chyba / bez odkazu)."""
    filename = build_filename(msg["date"], msg["category"], msg["title"], msg["original"])
    target = os.path.join(DOWNLOAD_DIR, filename)

    if msg["link_locator"] is None:
        print(f"  Přeskakuji (bez odkazu): {filename}")
        return 0

    count = 0
    if msg["link_type"] == "download":
        try:
            with page.expect_download(timeout=30_000) as dl_info:
                msg["link_locator"].dispatch_event("click")
            dl_info.value.save_as(target)
            already.add(filename)
            count += 1
            print(f"  Staženo: {filename}")
            time.sleep(0.3)
        except Exception as e:
            print(f"  Chyba při stahování '{filename}': {e}")

    elif msg["link_type"] == "zobrazit":
        try:
            msg["link_locator"].click()
            footer = msg["msg_locator"].locator(".InboxMessage-footer")
            footer.wait_for(state="visible", timeout=10_000)
            time.sleep(0.5)

            text_el = footer.locator("div").first
            text = text_el.inner_text().strip()
            txt_target = Path(target).with_suffix(".txt")
            txt_target.write_text(text, encoding="utf-8")
            already.add(txt_target.name)
            count += 1
            print(f"  Uložen text: {txt_target.name}")

            attach_links = footer.locator("a.i-l").all()
            for al in attach_links:
                orig = al.get_attribute("title", timeout=2_000) or ""
                orig_name = orig.split()[-1] if orig else "priloha"
                att_filename = build_filename(msg["date"], msg["category"], msg["title"], orig_name)
                att_target = os.path.join(DOWNLOAD_DIR, att_filename)
                if not os.path.exists(att_target):
                    with page.expect_download(timeout=30_000) as dl_info:
                        al.dispatch_event("click")
                    dl_info.value.save_as(att_target)
                    already.add(att_filename)
                    count += 1
                    print(f"  Stažena příloha: {att_filename}")
            time.sleep(0.3)
        except Exception as e:
            print(f"  Chyba při zobrazení '{filename}': {e}")

    return count


def main() -> None:
    try:
        from playwright.sync_api import sync_playwright
    except ImportError:
        print("Chybí playwright: pip install playwright && playwright install chrome")
        sys.exit(1)

    os.makedirs(DOWNLOAD_DIR, exist_ok=True)
    _delete_chrome_cert_policy()

    with sync_playwright() as p:
        context = p.chromium.launch_persistent_context(
            user_data_dir=CHROME_PROFILE,
            channel="chrome",
            headless=False,
            slow_mo=100,
            ignore_https_errors=True,
            accept_downloads=True,
            args=["--force-renderer-accessibility"],
            downloads_path=DOWNLOAD_DIR,
        )
        try:
            loaded = load_cookies(context)
            print(f"Cookies načtené z JSON: {loaded}")

            page = context.new_page()

            print("Naviguji na VZP Point schránku...")
            try:
                page.goto(INBOX_URL, wait_until="domcontentloaded", timeout=30_000)
            except Exception as e:
                print(f"Navigace: {e}")

            if page.url.startswith("https://auth.vzp.cz/signin"):
                print("Přihlašovací stránka — klikám na 'Certifikát'...")
                cert_btn = page.locator("a, button").filter(has_text=re.compile(r"certifikát", re.I)).first
                cert_btn.wait_for(state="visible", timeout=10_000)
                cert_btn.click(no_wait_after=True)
                print("Pokud se zobrazí dialog výběru certifikátu, vyberte ho ručně (max 60 s)...")
                time.sleep(60)
                page = context.new_page()
                try:
                    page.goto(INBOX_URL, wait_until="domcontentloaded", timeout=30_000)
                except Exception as e:
                    print(f"Navigace po auth: {e}")
                if not page.url.startswith("https://point.vzp.cz"):
                    print(f"Přihlášení selhalo. URL: {page.url}")
                    return

            print("Přihlášení OK.")
            page.wait_for_load_state("networkidle", timeout=15_000)

            already = set(os.listdir(DOWNLOAD_DIR))
            print(f"V archivu: {len(already)} souborů.")

            downloaded = 0
            processed = 0
            stop = False
            processed_ids = set()  # index pozic zpráv, které už jsme zpracovali

            while not stop:
                messages = collect_messages(page)
                new_in_batch = 0

                for i, msg in enumerate(messages):
                    if i in processed_ids:
                        continue
                    processed_ids.add(i)

                    filename = build_filename(msg["date"], msg["category"], msg["title"], msg["original"])

                    # Rozhodující test: už máme stejný název (nebo .txt variantu u 'zobrazit')?
                    txt_variant = str(Path(filename).with_suffix(".txt").name)
                    if filename in already or txt_variant in already:
                        print(f"[{processed+1}] Nalezena existující zpráva: {filename}")
                        print("Končím — starší zprávy jsou všechny stažené.")
                        stop = True
                        break

                    processed += 1
                    print(f"[{processed}] Nová zpráva: {filename}")
                    downloaded += download_message(page, msg, already)
                    new_in_batch += 1

                if stop:
                    break

                # Prošli jsme celý aktuálně načtený seznam a nic jsme nenašli → načti další stránku
                print(f"Aktuální stránka ({len(messages)} zpráv) bez existující — lazy-load dalších...")
                if not click_load_more(page):
                    print("Další zprávy už nejsou — končím.")
                    break

            print(f"\nHotovo. Nových zpráv: {processed}, stažených souborů: {downloaded}")

        finally:
            saved = save_cookies(context)
            print(f"Uloženo {saved} VZP cookies.")
            context.close()


if __name__ == "__main__":
    main()
