#!/usr/bin/env python3
"""
Automated Auction4Cars login using the credential saved in the macOS login
keychain, the same pattern as auto_login_cazana.py, auto_login_carwow.py,
auto_login_motorway.py and auto_login_dealerkit.py (Mark 2026-08-27: "update
DA, A4C, LE to use the auto login that DK, Cazana & MW & Carwow use").

The password is never printed, logged, written to a file, or returned from
any function here, only held in a local variable long enough to type it into
the page. It is read at run time from the macOS keychain via the `security`
command line tool, so it never lives in this repo or anywhere Claude (or
anyone reading this code) can see it.

Auction4Cars' own session cookie does not survive a fresh process launching
its own Chrome (checked live 2026-08-27), so, like Carwow and DealerKit and
unlike Motorway, this logs in through a fresh throwaway context and saves the
result to data/auction4cars_state.json, the same file every other
Auction4Cars read already uses via bidbrain.browser.open_reader_context.

The real "logged in" signal reused here (landing on /home or /live-auctions
on the real host) is the same one login.py's own auto detect already uses
for this exact site, not a new one invented for this script.

Auction4Cars' own login page sits behind a Termly cookie consent banner
(checked live 2026-08-27) that visually overlays the username field even
though Playwright reports the field itself as "visible", so this clicks
Preferences then Decline All first (the most privacy preserving choice,
matching this project's own standing rule on cookie banners) before ever
touching the real form. If Termly's own markup ever changes and neither
button can be found, this fails loudly rather than guessing at a different
flow.

One time setup, done by Mark, not by this script:
    python3 setup_credential.py auction4cars
  The first time this script runs, macOS may prompt for permission to read
  that keychain item. Choose "Always Allow" so future scheduled runs do not
  need anyone at the keyboard.

Usage:   python3 auto_login_auction4cars.py            headless, for real use
         python3 auto_login_auction4cars.py --headed    a visible window, to watch it work

This only ever logs in. It never reads stock or does anything else.
"""

import sys
import subprocess
from playwright.sync_api import sync_playwright
from bidbrain import browser, db

SERVER = "www.auction4cars.com"
LOGIN_URL = "https://www.auction4cars.com/?scrollToLogin=true"


def _keychain_lookup(server):
    """Return (account, password) for this server from the macOS login
    keychain, or (None, None) if nothing is saved. Never prints either
    value. Raises RuntimeError (with no secret in the message) if the
    `security` tool itself is missing, which should not happen on macOS."""
    try:
        pw = subprocess.run(
            ["security", "find-internet-password", "-s", server, "-w"],
            capture_output=True, text=True,
        )
    except FileNotFoundError:
        raise RuntimeError("The macOS `security` command line tool is not available.")
    if pw.returncode != 0:
        return None, None
    password = pw.stdout.rstrip("\n")

    meta = subprocess.run(
        ["security", "find-internet-password", "-s", server],
        capture_output=True, text=True,
    )
    account = None
    for line in meta.stdout.splitlines():
        line = line.strip()
        if line.startswith('"acct"'):
            start = line.find('="')
            if start != -1:
                account = line[start + 2:-1]
            break
    return account, password


def _decline_cookies(page):
    """Auction4Cars' Termly consent banner sits on top of the login form.
    Dismiss it the most privacy preserving way: Preferences then Decline
    All. A missing button is left alone rather than guessed at, the login
    itself will simply fail loudly further down if the overlay is still
    blocking the fields."""
    try:
        page.click('button:has-text("Preferences")', timeout=5000)
        page.wait_for_timeout(400)
        page.click('button:has-text("Decline All")', timeout=5000)
        page.wait_for_timeout(400)
    except Exception:
        pass


def login(headless=True):
    account, password = _keychain_lookup(SERVER)
    if not account or not password:
        raise RuntimeError(
            f"No saved login found for {SERVER}. Run: "
            f"python3 setup_credential.py auction4cars, then try again."
        )

    with sync_playwright() as p:
        b = p.chromium.launch(headless=headless, args=["--disable-blink-features=AutomationControlled"])
        ctx = b.new_context(viewport={"width": 1440, "height": 900})
        try:
            page = ctx.new_page()
            page.goto(LOGIN_URL, wait_until="domcontentloaded", timeout=30000)
            page.wait_for_timeout(1500)
            _decline_cookies(page)

            try:
                page.wait_for_selector("#username", timeout=15000)
            except Exception:
                raise RuntimeError(
                    "Auction4Cars' login page did not show the expected username field. "
                    "The page may have changed, check it by eye (python3 login.py auction4cars manual)."
                )
            page.fill("#username", account)
            page.fill("#password", password)
            password = None  # cleared as soon as it is no longer needed
            try:
                page.click('button[type="submit"]:has-text("Log in")', timeout=5000)
            except Exception:
                raise RuntimeError("Could not find the Auction4Cars login submit button.")

            # Same real detection login.py's own auto detect already uses
            # for this site: the real dealer home or the live auctions list,
            # never a bare "not still on the login page" guess.
            logged_in = False
            waited = 0
            while waited < 15000:
                page.wait_for_timeout(500)
                waited += 500
                try:
                    u = page.url
                except Exception:
                    continue
                if "www.auction4cars.com" in u and ("/home" in u or "/live-auctions" in u):
                    logged_in = True
                    break
            if not logged_in:
                err = page.query_selector('[class*="error" i], [role="alert"]')
                detail = err.inner_text().strip() if err else (
                    "the page never reached the real dealer home or live auctions list, "
                    "a wrong password or a blocked consent banner may be the cause")
                raise RuntimeError(f"Auction4Cars login did not succeed: {detail}")

            ctx.storage_state(path=browser.state_path("auction4cars"))
            db.record_site_health("auction4cars", True, "")
            print("Logged in to Auction4Cars. Session saved.")
        finally:
            ctx.close()
            b.close()


if __name__ == "__main__":
    headless = "--headed" not in sys.argv
    try:
        login(headless=headless)
    except Exception as e:
        print(f"FAILED: {e}")
        sys.exit(1)
