#!/usr/bin/env python3
"""
Automated Motorway login using the credential saved in the macOS login
keychain, the same pattern as auto_login_cazana.py and auto_login_carwow.py
(Steven 2026-08-26: "is there any way to automate it like we have the
cazana/carwow ones?", after a real, dead Motorway session blocked a
purchases sync).

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.

One real difference from Carwow: Motorway's own login lives in the SHARED
PERSISTENT BROWSER PROFILE (bidbrain.browser.open_context, data/browser_
profile), not a saved storage_state.json the way Carwow's does (see
bidbrain.browser.open_reader_context's own docstring: no motorway_state.json
exists, every Motorway read falls back to the persistent profile). So this
script logs in through that SAME persistent profile rather than a fresh,
throwaway context, and there is nothing separate to save afterward, the
profile itself is what every other Motorway read and write already relies
on. Only one process may use that profile at a time (see open_context's own
docstring), so this must never run at the same time as any other headed or
headless Motorway pass, purchases sync, or the daily run itself, which is
why its own scheduled slot (see the matching .plist) sits well clear of
every other job that touches Motorway.

Motorway's own login page carries a genuine "Keep me signed in on this
device" checkbox, ticked here since the whole point is a session that
outlasts a single browser process; this may be exactly why Motorway's
session has needed daily attention before now, while Cazana's own 30 day
one rarely has.

Motorway's login page is a plain email/password form (checked live
2026-08-26, no CAPTCHA visible), same shape as Carwow's; if a CAPTCHA or
some other block ever does appear, this fails loudly rather than guessing.

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

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

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

SERVER = "pro.motorway.co.uk"
LOGIN_URL = browser.SITES["motorway"]["login_url"]
# A logged in dealer page, any one will do, just needs a URL not reachable
# without a real session. Matches login.py's own real time auto detect
# signal for this exact site.
CHECK_URL = "https://pro.motorway.co.uk/vehicles"


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 _looks_logged_out(url):
    """The same real time signal login.py's own auto detect already uses for
    this site: the dealer host, but still on the sign in form's own path."""
    parts = urlparse(url)
    return not (parts.netloc == "pro.motorway.co.uk"
                and "login" not in parts.path and "signin" not in parts.path)


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 motorway, then try again."
        )

    with sync_playwright() as p:
        ctx = browser.open_context(p, headless=headless)
        try:
            page = ctx.pages[0] if ctx.pages else ctx.new_page()
            page.goto(LOGIN_URL, wait_until="domcontentloaded", timeout=30000)
            page.wait_for_timeout(1500)
            # The persistent profile can already be logged in from an earlier
            # session (caught live 2026-08-26: /signin redirected straight to
            # the real dealer homepage, "Live sale", "Bids & offers",
            # "Purchases", "Dashboard" all visible, no login form to find at
            # all), in which case there is genuinely nothing to log into, not
            # a failure. Only fall through to the real form when Motorway
            # actually shows one.
            if not _looks_logged_out(page.url):
                db.record_site_health("motorway", True, "")
                print("Already logged in to Motorway. Nothing to do.")
                return
            try:
                page.wait_for_selector("#username", timeout=15000)
            except Exception:
                raise RuntimeError(
                    "Motorway's login page did not show the expected email field. "
                    "The page may have changed, check it by eye (python3 login.py motorway)."
                )
            page.fill("#username", account)
            page.fill("#password", password)
            password = None  # cleared as soon as it is no longer needed
            try:
                cb = page.query_selector("#remember")
                if cb and not cb.is_checked():
                    cb.click()
            except Exception:
                pass  # a missing "keep me signed in" box is not worth failing over
            try:
                page.click('button[type="submit"]', timeout=5000)
            except Exception:
                raise RuntimeError("Could not find the Motorway login submit button.")
            page.wait_for_timeout(2000)

            # A wrong password shows a real, real time error right here, on
            # THIS page, straight after the submit (found live 2026-08-27,
            # building the second account's own version of this script,
            # ".mw-feedback-tooltip-content", a real "Your username or
            # password were incorrect" tooltip). Checked here, before ever
            # navigating away: checking only after the CHECK_URL navigation
            # below is a genuinely DIFFERENT page load, one with no failed
            # submit of its own to show a tooltip for, so a real, readable
            # reason came back blank every time, caught live rather than
            # trusted from the code alone.
            err = page.query_selector(
                '.mw-feedback-tooltip-content, [class*="error" i], [role="alert"]')
            if err:
                detail = err.inner_text().strip()
                raise RuntimeError(f"Motorway login did not succeed: {detail}")

            # No fixed "logged in" selector to wait on here; instead land on
            # a real dealer page and use the same dead-session check
            # login.py's own auto detect already relies on. A captcha or a
            # changed page lands here, never guessed which, just fail
            # loudly.
            try:
                page.goto(CHECK_URL, wait_until="domcontentloaded", timeout=30000)
                page.wait_for_timeout(2000)
            except Exception:
                raise RuntimeError("Motorway did not respond after logging in.")
            if _looks_logged_out(page.url):
                raise RuntimeError(
                    "Motorway login did not succeed: still on the sign in page after "
                    "submitting, a captcha or bot check may have blocked it.")

            # Nothing to save separately: this IS the shared persistent
            # profile every other Motorway read and write already uses, the
            # login lives in it directly.
            # 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("motorway", True, "")
            print("Logged in to Motorway. Session saved.")
        finally:
            ctx.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)
