#!/usr/bin/env python3
"""
chatgpt-login/scripts/login.py
--------------------------------
Logs into ChatGPT using camoufox (anti-detection browser) + the residential
proxy. Credentials are read from tc creds; a workspace can optionally be
specified. Saves the authenticated session to a JSON file so future runs can
skip the login step entirely.

Usage:
    python3 login.py [--workspace "Name of Workspace"] [--session /path/to/session.json]

Environment overrides (useful for testing without tc):
    CHATGPT_USERNAME   — OpenAI / ChatGPT email
    CHATGPT_PASSWORD   — OpenAI / ChatGPT password
    CHATGPT_PROXY      — SOCKS5 proxy URL (defaults to socks5://172.20.0.1:1055)
    CHATGPT_SESSION    — Path to save session JSON
"""

import argparse
import os
import subprocess
import sys
import time

from camoufox.sync_api import Camoufox

# ── Config ──────────────────────────────────────────────────────────────────

DEFAULT_PROXY    = "socks5://172.20.0.1:1055"
DEFAULT_SESSION  = "/workspace/group/chatgpt-session.json"
SCREENSHOT_DIR   = "/workspace/group/screenshots/chatgpt-login"

# ── Helpers ─────────────────────────────────────────────────────────────────

def tc_creds_get(name: str) -> str:
    """Read a credential value from tc creds."""
    result = subprocess.run(["tc", "creds", "get", name],
                            capture_output=True, text=True)
    return result.stdout.strip()


def tc_proxy() -> str:
    """Get the residential proxy URL from tc proxy."""
    result = subprocess.run(["tc", "proxy"], capture_output=True, text=True)
    url = result.stdout.strip()
    return url if url and not result.returncode else ""


def resolve_config(args) -> dict:
    """Resolve credentials + proxy from env > tc creds > defaults."""
    username = (getattr(args, "username", None)
                or os.environ.get("CHATGPT_USERNAME")
                or tc_creds_get("chatgpt_username"))
    password = (getattr(args, "password", None)
                or os.environ.get("CHATGPT_PASSWORD")
                or tc_creds_get("chatgpt_password"))

    if not username or not password:
        print("[ERROR] ChatGPT credentials not found.\n"
              "  Store them with:\n"
              "    tc creds set chatgpt_username <email>\n"
              "    tc creds set chatgpt_password <password>",
              file=sys.stderr)
        sys.exit(1)

    proxy = (os.environ.get("CHATGPT_PROXY")
             or tc_proxy()
             or DEFAULT_PROXY)

    session_path = (os.environ.get("CHATGPT_SESSION")
                    or args.session
                    or DEFAULT_SESSION)

    return {
        "username":     username,
        "password":     password,
        "proxy":        proxy,
        "session_path": session_path,
        "workspace":    args.workspace,
    }


def shot(page, name: str, timeout: int = 60_000) -> None:
    os.makedirs(SCREENSHOT_DIR, exist_ok=True)
    path = os.path.join(SCREENSHOT_DIR, f"{name}.png")
    try:
        page.screenshot(path=path, timeout=timeout)
        print(f"  [screenshot] {path}")
    except Exception as exc:
        print(f"  [screenshot failed] {name}: {exc}")


# ── Login flow ───────────────────────────────────────────────────────────────

def login(cfg: dict) -> bool:
    """
    Perform the full OpenAI email+password login flow.
    Returns True if the session was saved successfully.
    """
    proxy_cfg = {"server": cfg["proxy"]} if cfg["proxy"] else None

    with Camoufox(headless=True, proxy=proxy_cfg, geoip=bool(proxy_cfg)) as browser:
        context = browser.new_context()
        page    = context.new_page()

        # 1 ── Landing / Login button
        print("[*] Opening ChatGPT login page...")
        page.goto("https://chatgpt.com/auth/login",
                  wait_until="domcontentloaded", timeout=30_000)
        time.sleep(3)
        shot(page, "01_landing")

        try:
            page.get_by_role("button", name="Log in").click(timeout=10_000)
            print("[+] Clicked 'Log in'")
        except Exception:
            try:
                page.locator("text=Log in").first.click(timeout=5_000)
            except Exception:
                pass  # May already be on the auth page
        time.sleep(3)
        print(f"    URL: {page.url}")

        # 2 ── Email
        print("[*] Filling email...")
        page.wait_for_selector(
            "input[type='email'], input[name='email'], "
            "input[id='email'], input[id='username']",
            timeout=15_000)
        page.locator(
            "input[type='email'], input[name='email'], "
            "input[id='email'], input[id='username']"
        ).first.fill(cfg["username"])

        try:
            page.get_by_role("button", name="Continue").click(timeout=5_000)
        except Exception:
            try:
                page.locator("button[type='submit']").first.click(timeout=5_000)
            except Exception:
                page.keyboard.press("Enter")
        print("[+] Email submitted")
        time.sleep(3)
        print(f"    URL: {page.url}")

        # 3 ── Password (may need to click "Continue with password" first)
        try:
            page.wait_for_selector("input[type='password']", timeout=8_000)
            print("[+] Password field found directly")
        except Exception:
            print("[!] Looking for 'Continue with password' link...")
            for label in ("Continue with password", "Use password"):
                try:
                    page.locator(f"text={label}").click(timeout=5_000)
                    print(f"[+] Clicked '{label}'")
                    time.sleep(2)
                    break
                except Exception:
                    pass

        page.wait_for_selector("input[type='password']", timeout=10_000)
        page.locator("input[type='password']").first.fill(cfg["password"])
        print("[+] Password filled")
        shot(page, "02_password_filled")

        try:
            page.get_by_role("button", name="Continue").click(timeout=5_000)
        except Exception:
            try:
                page.locator("button[type='submit']").first.click(timeout=5_000)
            except Exception:
                page.keyboard.press("Enter")
        print("[+] Password submitted")
        time.sleep(4)
        print(f"    URL: {page.url}")

        # 4 ── Workspace selector (shown when account belongs to multiple orgs)
        try:
            page.wait_for_url("**/workspace**", timeout=20_000)
            time.sleep(2)
            shot(page, "03_workspace_selector")
            print(f"[*] Workspace selector visible. URL: {page.url}")

            target_workspace = cfg.get("workspace")
            if target_workspace:
                # Click the requested workspace
                ws = page.locator(f"text={target_workspace}").first
                ws.wait_for(timeout=10_000)
                ws.click()
                print(f"[+] Selected workspace: {target_workspace}")
            else:
                # List available workspaces and pick the first one
                ws_items = page.locator("text=Workspace, text=account").all_text_contents()
                print(f"[!] No workspace specified. Available: {ws_items}")
                print("    Clicking the first option...")
                page.locator("div[data-testid], li, .workspace-item").first.click()

        except Exception:
            print("[*] No workspace selector found — continuing")

        # 5 ── Wait for chatgpt.com to fully load
        print("[*] Waiting for ChatGPT to load...")
        try:
            page.wait_for_url("*chatgpt.com*", timeout=30_000)
            print(f"[+] On chatgpt.com: {page.url}")
        except Exception:
            print(f"[!] URL: {page.url}")

        try:
            page.wait_for_load_state("networkidle", timeout=30_000)
        except Exception:
            pass  # Partial load is usually fine for session capture

        time.sleep(5)
        final_url = page.url
        shot(page, "04_final_state")
        print(f"\n[*] Final URL: {final_url}")

        # 6 ── Save session
        if "chatgpt.com" in final_url and "auth.openai.com" not in final_url:
            os.makedirs(os.path.dirname(cfg["session_path"]), exist_ok=True)
            context.storage_state(path=cfg["session_path"])
            print(f"\n✓ Logged in successfully!")
            print(f"✓ Session saved → {cfg['session_path']}")
            return True
        else:
            print(f"\n✗ Login may have failed. Final URL: {final_url}")
            print("  Check screenshots in:", SCREENSHOT_DIR)
            return False


# ── Entry point ──────────────────────────────────────────────────────────────

def main():
    parser = argparse.ArgumentParser(description="Log into ChatGPT via camoufox.")
    parser.add_argument("--workspace", default=None,
                        help="Workspace name to select (e.g. 'Devit Workspace')")
    parser.add_argument("--session",   default=None,
                        help=f"Path to save session JSON (default: {DEFAULT_SESSION})")
    parser.add_argument("--username",  default=None,
                        help="ChatGPT email (overrides env var and tc creds)")
    parser.add_argument("--password",  default=None,
                        help="ChatGPT password (overrides env var and tc creds)")
    args = parser.parse_args()

    cfg = resolve_config(args)
    print(f"[*] Using proxy: {cfg['proxy']}")
    print(f"[*] Session will be saved to: {cfg['session_path']}")
    if cfg["workspace"]:
        print(f"[*] Target workspace: {cfg['workspace']}")

    ok = login(cfg)
    sys.exit(0 if ok else 1)


if __name__ == "__main__":
    main()
