#!/usr/bin/env python3
"""
Automated Carwow login using the credential saved in the macOS login
keychain, so a dead Carwow session (caught doing this silently on
2026-08-25, see CLAUDE.md) can be recovered without Steven sitting down to
log in by hand.

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.

Carwow's own login runs through Auth0, a platform with configurable captcha
and bot detection options available to it. This script cannot know in
advance whether one is active on Steven's account; if a login does not reach
the real stock list, it fails loudly (never guesses, never retries blind)
rather than pretending to have worked.

One time setup, done by Steven, not by this script:
    ~/BidBrain/.venv/bin/python setup_credential.py carwow
  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_carwow.py            headless, for real use
         python3 auto_login_carwow.py --headed    a visible window, to watch it work

This only ever logs in. It never reads stock or bids on anything.
"""

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

SERVER = "dealers.carwow.co.uk"
LOGIN_URL = "https://dealers.carwow.co.uk/dealers/login"
STOCK_URL = browser.SITES["carwow"]["stock_url"]


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 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"~/BidBrain/.venv/bin/python setup_credential.py carwow, 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)
            try:
                page.wait_for_selector('#username', timeout=15000)
            except Exception:
                raise RuntimeError(
                    "Carwow's login page did not show the expected username field. "
                    "The page may have changed, check it by eye (python3 login.py carwow)."
                )
            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"]', timeout=5000)
            except Exception:
                raise RuntimeError("Could not find the Carwow login submit button.")

            # No fixed "logged in" selector to wait on here (Auth0's own
            # redirect chain varies); instead land on the real stock page and
            # use the same dead-session check the reader itself relies on.
            # A wrong password, a captcha challenge, or a changed page all
            # land here, never guessed which, just fail loudly.
            try:
                page.goto(STOCK_URL, wait_until="domcontentloaded", timeout=30000)
                page.wait_for_timeout(2000)
            except Exception:
                raise RuntimeError("Carwow did not respond after logging in.")
            if _looks_logged_out(page.url):
                err = page.query_selector('[class*="error" i], [role="alert"]')
                detail = err.inner_text().strip() if err else (
                    "still on a login page after submitting, a wrong password or "
                    "a captcha/bot check may have blocked it")
                raise RuntimeError(f"Carwow login did not succeed: {detail}")

            ctx.storage_state(path=browser.state_path("carwow"))
            # A successful login is real, current evidence the site is
            # reachable, worth clearing any earlier real-read failure that
            # would otherwise sit there stale until the next successful
            # read happens to come along (Steven 2026-08-26, caught live).
            db.record_site_health("carwow", True, "")
            print("Logged in to Carwow. 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)
