"""Browser identity personas + cookie policies.

The "lock everything down" approach (Firefox RFP + WebRTC off + cookies blocked)
keeps you safe from fingerprinting but makes the machine *look weird* — sites
flag you as suspicious and ban / captcha you. Worse: very few users use that
config, so RFP-on is itself a fingerprint.

Two strategies are exposed:

  • **Blend-in personas** — mimic the most common Windows-Chrome-US-en setup.
    JS / cookies / WebGL all work; everything looks normal; only WebRTC is
    blocked (because that leaks the real IP behind the proxy). The proxy
    chain itself does the actual hiding.

  • **Hardened** — full RFP / blocked WebRTC / strict tracking / FPI. Stand-out
    but maximum block. Same behavior as the original profile.

Cookie modes are independent of persona.  Each mode expresses a complete
policy: which cookies to accept, lifetime, whether to wipe on close, and
whether to partition 3rd-party storage.
"""
from __future__ import annotations

from dataclasses import dataclass


# ── Personas ──────────────────────────────────────────────────────────────────

PERSONAS: list[str] = [
    "blend_windows_chrome",
    "blend_windows_chrome_laptop",
    "blend_windows_firefox",
    "blend_windows_edge",
    "blend_mac_safari",
    "blend_mac_chrome",
    "blend_linux_firefox",
    "hardened",
    "custom",
]

PERSONA_LABELS: dict[str, str] = {
    "blend_windows_chrome":        "Blend — Win10 + Chrome 124 (most common, US-en)",
    "blend_windows_chrome_laptop": "Blend — Win11 + Chrome 124 laptop 1366×768",
    "blend_windows_firefox":       "Blend — Win10 + Firefox 128 (US-en)",
    "blend_windows_edge":          "Blend — Win11 + Edge 124 (corporate look)",
    "blend_mac_safari":            "Blend — macOS 14 + Safari 17 (US-en)",
    "blend_mac_chrome":            "Blend — macOS 14 + Chrome 124 (US-en)",
    "blend_linux_firefox":         "Blend — Ubuntu + Firefox 128 (en-US)",
    "hardened":                    "Hardened — RFP + FPI + block all (stands out)",
    "custom":                      "Custom — use individual hardening toggles",
}


@dataclass(frozen=True)
class Persona:
    """A user-agent / locale / timezone / screen tuple that mimics a real,
    common configuration."""
    key: str
    user_agent: str
    accept_language: str
    timezone: str
    screen_w: int
    screen_h: int
    platform: str
    locale: str


PERSONA_DATA: dict[str, Persona] = {
    "blend_windows_chrome": Persona(
        key="blend_windows_chrome",
        user_agent=(
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
            "(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
        ),
        accept_language="en-US,en;q=0.9",
        timezone="America/New_York",
        screen_w=1920, screen_h=1080,
        platform="Win32",
        locale="en-US",
    ),
    "blend_windows_chrome_laptop": Persona(
        key="blend_windows_chrome_laptop",
        user_agent=(
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
            "(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
        ),
        accept_language="en-US,en;q=0.9",
        timezone="America/Chicago",
        screen_w=1366, screen_h=768,
        platform="Win32",
        locale="en-US",
    ),
    "blend_windows_firefox": Persona(
        key="blend_windows_firefox",
        user_agent=(
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) "
            "Gecko/20100101 Firefox/128.0"
        ),
        accept_language="en-US,en;q=0.5",
        timezone="America/New_York",
        screen_w=1920, screen_h=1080,
        platform="Win32",
        locale="en-US",
    ),
    "blend_windows_edge": Persona(
        key="blend_windows_edge",
        user_agent=(
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
            "(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"
        ),
        accept_language="en-US,en;q=0.9",
        timezone="America/Chicago",
        screen_w=1920, screen_h=1080,
        platform="Win32",
        locale="en-US",
    ),
    "blend_mac_safari": Persona(
        key="blend_mac_safari",
        user_agent=(
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
            "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15"
        ),
        accept_language="en-US,en;q=0.9",
        timezone="America/Los_Angeles",
        screen_w=1680, screen_h=1050,
        platform="MacIntel",
        locale="en-US",
    ),
    "blend_mac_chrome": Persona(
        key="blend_mac_chrome",
        user_agent=(
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
            "(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
        ),
        accept_language="en-US,en;q=0.9",
        timezone="America/Los_Angeles",
        screen_w=1440, screen_h=900,
        platform="MacIntel",
        locale="en-US",
    ),
    "blend_linux_firefox": Persona(
        key="blend_linux_firefox",
        user_agent=(
            "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0) "
            "Gecko/20100101 Firefox/128.0"
        ),
        accept_language="en-US,en;q=0.5",
        timezone="America/New_York",
        screen_w=1920, screen_h=1080,
        platform="Linux x86_64",
        locale="en-US",
    ),
}


# ── Cookie policies ───────────────────────────────────────────────────────────

@dataclass(frozen=True)
class CookiePolicy:
    """
    Complete Firefox cookie configuration expressed as a single composable unit.

    behavior       : network.cookie.cookieBehavior
                       0 = accept all
                       1 = block 3rd-party
                       2 = block ALL cookies
                       3 = block 3rd-party from unvisited sites
                       4 = block cross-site tracking (ETP Strict)
                       5 = block cross-site + social media trackers
    lifetime       : network.cookie.lifetimePolicy
                       0 = normal (respect Set-Cookie expires)
                       2 = session-only (all cookies expire on close)
    partition      : Total Cookie Protection — partition 3rd-party storage
                     by the top-level site (network.cookie.cookieBehavior.optInPartitioning)
    clear_cookies  : privacy.clearOnShutdown.cookies
    clear_cache    : privacy.clearOnShutdown.cache
    clear_history  : privacy.clearOnShutdown.history
    clear_ls       : privacy.clearOnShutdown.localStorage + indexedDB
    clear_formdata : privacy.clearOnShutdown.formdata
    sanitize       : privacy.sanitize.sanitizeOnShutdown (master switch)
    """
    behavior:      int  = 1
    lifetime:      int  = 0
    partition:     bool = False
    sanitize:      bool = False
    clear_cookies: bool = False
    clear_cache:   bool = False
    clear_history: bool = False
    clear_ls:      bool = False
    clear_formdata: bool = False


# Every cookie mode is a complete CookiePolicy — no guesswork in profile.py.
COOKIE_POLICIES: dict[str, CookiePolicy] = {

    # ── Permissive ──────────────────────────────────────────────────────────

    "accept_all": CookiePolicy(
        behavior=0, lifetime=0,
        # No clearing, no blocking — maximum site compatibility.
    ),

    "accept_all_session": CookiePolicy(
        behavior=0, lifetime=2,
        sanitize=True, clear_cookies=True, clear_ls=True,
        # Accept all cookies while browsing but wipe them when the
        # browser closes.  Good for signup / form-filling sessions.
    ),

    # ── Standard 3rd-party blocking ────────────────────────────────────────

    "block_third_party": CookiePolicy(
        behavior=1, lifetime=0,
        # Block 3rd-party, accept 1st-party with normal lifetime.
        # Recommended baseline — most sites work fine.
    ),

    "block_third_party_session": CookiePolicy(
        behavior=1, lifetime=2,
        sanitize=True, clear_cookies=True, clear_cache=True, clear_ls=True,
        # Block 3rd-party AND treat all accepted cookies as session-only.
        # Nothing persists.  Use for anonymous sessions.
    ),

    # ── Tracker-focused blocking ────────────────────────────────────────────

    "block_third_party_trackers": CookiePolicy(
        behavior=4, lifetime=0,
        # Firefox ETP Strict mode: only blocks known trackers, not ALL
        # 3rd-party cookies.  Best blend-in option — same as Firefox default.
    ),

    "block_social_trackers": CookiePolicy(
        behavior=5, lifetime=0,
        # Block cross-site cookies AND social-media tracking cookies
        # (Facebook, Twitter pixels, etc.).  Stricter than ETP Strict but
        # still allows most logins.
    ),

    "block_unvisited": CookiePolicy(
        behavior=3, lifetime=0,
        # Block 3rd-party from sites the user has never visited.  Very light
        # — almost invisible to sites; good when you need max compatibility.
    ),

    # ── Partitioned storage (Total Cookie Protection) ───────────────────────

    "partitioned_tcp": CookiePolicy(
        behavior=1, lifetime=0, partition=True,
        # Block 3rd-party AND enable Total Cookie Protection: each site
        # gets its own isolated cookie jar so cross-site tracking via
        # cookie sync is impossible.  Recommended for blend-in + privacy.
    ),

    "partitioned_session": CookiePolicy(
        behavior=1, lifetime=2, partition=True,
        sanitize=True, clear_cookies=True, clear_cache=True,
        clear_ls=True, clear_formdata=True,
        # Partitioned + session-only + full wipe on close.  Leaves no
        # persistent state on disk after the browser exits.
    ),

    # ── Maximum wipe ───────────────────────────────────────────────────────

    "session_only": CookiePolicy(
        behavior=0, lifetime=2,
        sanitize=True, clear_cookies=True,
        # All cookies accepted but expire when the browser closes.
        # Note: localStorage is NOT cleared here — only cookies.
    ),

    "ghost_mode": CookiePolicy(
        behavior=1, lifetime=2,
        sanitize=True, clear_cookies=True, clear_cache=True,
        clear_history=True, clear_ls=True, clear_formdata=True,
        partition=True,
        # Maximum ephemeral session: block 3rd-party, TCP partitioning,
        # session-only lifetime, full wipe of cookies + cache + history +
        # localStorage/IndexedDB + formdata on every close.  Zero disk trace.
    ),

    "block_all": CookiePolicy(
        behavior=2, lifetime=0,
        # Block ALL cookies.  Most login-dependent sites will break.
        # Only useful for read-only scraping sessions.
    ),
}

COOKIE_MODES: list[str] = list(COOKIE_POLICIES)

COOKIE_LABELS: dict[str, str] = {
    "accept_all":                "Accept all — maximum compatibility (cookies persist)",
    "accept_all_session":        "Accept all, session only — wipe cookies on close",
    "block_third_party":         "Block 3rd-party — recommended baseline (persists 1st-party)",
    "block_third_party_session": "Block 3rd-party + session — nothing persists",
    "block_third_party_trackers":"Block trackers only — ETP Strict (Firefox default-strict)",
    "block_social_trackers":     "Block social + cross-site trackers (Facebook pixel, etc.)",
    "block_unvisited":           "Block 3rd-party from unvisited sites — lightest option",
    "partitioned_tcp":           "Partitioned (TCP) — each site gets isolated 3rd-party jar",
    "partitioned_session":       "Partitioned + session — isolated jars, full wipe on close",
    "session_only":              "Session only — all cookies expire on close (no partition)",
    "ghost_mode":                "Ghost mode — partitioned + session + full disk wipe on close",
    "block_all":                 "Block ALL cookies — breaks most logins",
}


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

def get_cookie_policy(mode: str) -> CookiePolicy:
    return COOKIE_POLICIES.get(mode, COOKIE_POLICIES["block_third_party"])


# Legacy shims kept for code that still calls these directly.
def cookie_behavior_value(mode: str) -> int:
    return get_cookie_policy(mode).behavior


def cookie_session_only(mode: str) -> bool:
    return get_cookie_policy(mode).lifetime == 2


def get_persona(key: str) -> Persona | None:
    return PERSONA_DATA.get(key)


def is_blend_persona(key: str) -> bool:
    return key.startswith("blend_")
