"""
Přihlášení na portál ČPZP pomocí certifikátu.

Flow:
  1. GET /app/login/ → session cookie + csrfCert token + challenge (certificateLoginKey)
  2. Podepiš challenge certifikátem (PKCS7 detached, RSA + SHA-256)
  3. POST /app/ s form-data: csrfCert=<token>&sign=<podpis_base64_der>
  4. Ulož cookies do cpzp_cookies.json

POUŽITÍ:
  pip install requests cryptography beautifulsoup4
  python 01_prihlaseni.py
"""

import base64
import json
import os
import re

import requests
from bs4 import BeautifulSoup
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.serialization import pkcs7, pkcs12

def _parse_js_str(js_expr: str) -> str:
    """Převede JS string expression ('a' + String.fromCharCode(13,10) + 'b') na Python string."""
    parts = re.findall(r"'([^']*)'|String\.fromCharCode\(([\d,\s]+)\)", js_expr)
    result = []
    for str_part, chars_part in parts:
        if str_part is not None and (str_part or not chars_part):
            result.append(str_part)
        elif chars_part:
            result.append("".join(chr(int(c.strip())) for c in chars_part.split(",")))
    return "".join(result)


PFX_PATH     = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../Certificates/MBQualifiedCert.pfx"))
PFX_PASSWORD = b"Vlado7309208104++"
COOKIES_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "cpzp_cookies.json"))

BASE_URL  = "https://portal.cpzp.cz"
LOGIN_URL = f"{BASE_URL}/app/login/"
POST_URL  = f"{BASE_URL}/app/"


def main() -> None:
    session = requests.Session()
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Origin": BASE_URL,
        "Referer": LOGIN_URL,
    })

    # 1. Načti login stránku → session cookie + HTML s tokenem a challengem
    r = session.get(LOGIN_URL)
    r.raise_for_status()

    soup = BeautifulSoup(r.content, "html.parser", from_encoding="utf-8")

    # Extrahuj csrfCert z formuláře frmPrihlasCert
    csrf_input = soup.find("form", {"name": "frmPrihlasCert"})
    if not csrf_input:
        raise RuntimeError("Formulář frmPrihlasCert nenalezen")
    csrf_cert = csrf_input.find("input", {"name": "csrfCert"})["value"]

    # Extrahuj challenge z JS — formát: 'část'+ String.fromCharCode(13, 10) +'část'
    html = r.content.decode("utf-8")  # vynutit UTF-8
    match = re.search(r"certificateLoginKey\s*:\s*(.+?)(?=,\s*\n|\n\s*maxHeight)", html, re.DOTALL)
    if not match:
        raise RuntimeError("certificateLoginKey nenalezen v HTML")
    challenge = _parse_js_str(match.group(1))
    print(f"Challenge: {challenge[:80]}...")

    # 2. Podepis certifikátem (PKCS7 detached, RSA + SHA-256, bez CA řetězu)
    with open(PFX_PATH, "rb") as f:
        private_key, cert, _ = pkcs12.load_key_and_certificates(f.read(), PFX_PASSWORD)

    pem_podpis = (
        pkcs7.PKCS7SignatureBuilder()
        .set_data(challenge.encode("utf-8"))
        .add_signer(cert, private_key, hashes.SHA256())
        .sign(serialization.Encoding.PEM, [pkcs7.PKCS7Options.DetachedSignature])
    )

    podpis_pem = pem_podpis.decode("ascii").strip()

    # 3. Přihlas se (POST form-data)
    r = session.post(POST_URL, data={
        "csrfCert": csrf_cert,
        "sign": podpis_pem,
    }, headers={
        "Content-Type": "application/x-www-form-urlencoded",
        "Referer": LOGIN_URL,
    })
    r.raise_for_status()

    # Ověř přihlášení — po úspěchu je v URL /app/ a stránka neobsahuje login formu
    if "frmPrihlasCert" in r.text:
        print("Přihlášení selhalo — server vrátil login stránku znovu")
        return

    print("Přihlášení úspěšné!")

    # 4. Ulož cookies
    cookies = [
        {
            "name":     c.name,
            "value":    c.value,
            "domain":   c.domain if c.domain.startswith(".") else "." + c.domain,
            "path":     c.path or "/",
            "expires":  int(c.expires) if c.expires else -1,
            "secure":   bool(c.secure),
            "httpOnly": False,
            "sameSite": "Lax",
        }
        for c in session.cookies
    ]
    with open(COOKIES_FILE, "w", encoding="utf-8") as f:
        json.dump(cookies, f, indent=2, ensure_ascii=False)
    print(f"Ulozeno {len(cookies)} cookies -> {COOKIES_FILE}")


if __name__ == "__main__":
    main()
