"""
Constants and configuration for the auto clicker application.
"""

import os
from dotenv import load_dotenv
import boto3

# Load environment variables from .env file
load_dotenv()

# Derive environment and local-dev flag early so we can source secrets correctly
ENV = os.getenv("ENV", "local").lower()
LOCAL_DEV = os.getenv("LOCAL_DEV", "true" if ENV == "local" else "false").lower() == "true"

# Font configurations
FONT = ('Segoe UI', 10)
HEADER_FONT = ('Segoe UI', 14, 'bold')
SIDEBAR_FONT = ('Segoe UI', 11, 'bold')

# UI Dimensions (allow env overrides)
def _int_env(name: str, default: int) -> int:
    try:
        raw = os.getenv(name, None)
        return int(raw) if raw is not None and str(raw).strip() != "" else default
    except Exception:
        return default

MINIMIZED_WIDTH = _int_env("UI_MIN_WIDTH", 100)
MINIMIZED_HEIGHT = _int_env("UI_MIN_HEIGHT", 340)
FULL_WIDTH = _int_env("UI_FULL_WIDTH", 700)
FULL_HEIGHT = _int_env("UI_FULL_HEIGHT", 400)
FULL_HEIGHT_WITH_DEBUG = _int_env("UI_FULL_HEIGHT_DEBUG", 600)

# UI scaling (Tk scaling factor). 1.0 = 100%, 1.25 = 125%, etc.
try:
    UI_SCALE = float(os.getenv("UI_SCALE", os.getenv("TK_SCALING", "1.0")))
except Exception:
    UI_SCALE = 1.0

# Colors
BACKGROUND_COLOR = '#e5e5e5'
CARD_BACKGROUND = '#fff'
MINIMIZED_BACKGROUND = '#f8f9fa'
BORDER_COLOR = '#ddd'
TEXT_COLOR = '#222'
PRIMARY_COLOR = '#007bff'
RECORDING_COLOR = '#d6336c'
PLAY_COLOR = '#228be6'
STOP_COLOR = '#495057'

# Grid overlay colors (RGBA where applicable)
# Override via env vars GRID_LINE_COLOR, GRID_LABEL_TEXT_COLOR, GRID_LABEL_BG_COLOR as comma-separated RGBA
def _parse_rgba_env(key: str, default: tuple[int, int, int, int]) -> tuple[int, int, int, int]:
    try:
        raw = os.getenv(key, None)
        if not raw:
            return default
        parts = [int(p.strip()) for p in raw.split(',')]
        if len(parts) == 3:
            parts.append(255)
        if len(parts) != 4:
            return default
        r, g, b, a = parts
        return (max(0, min(255, r)), max(0, min(255, g)), max(0, min(255, b)), max(0, min(255, a)))
    except Exception:
        return default

GRID_LINE_COLOR_RGBA = _parse_rgba_env("GRID_LINE_COLOR", (0, 255, 0, 255))
GRID_LABEL_TEXT_COLOR_RGBA = _parse_rgba_env("GRID_LABEL_TEXT_COLOR", (255, 255, 0, 255))
GRID_LABEL_BG_COLOR_RGBA = _parse_rgba_env("GRID_LABEL_BG_COLOR", (0, 0, 0, 160))
# Column/row label font size
try:
    GRID_LABEL_FONT_SIZE = int(os.getenv("GRID_LABEL_FONT_SIZE", "18"))
except Exception:
    GRID_LABEL_FONT_SIZE = 18

# OpenAI Configuration
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")  # Prefer environment variable locally

# If not local, attempt to fetch the key from AWS SSM Parameter Store
if ENV != "local" and not OPENAI_API_KEY:
    try:
        param_name = os.getenv("OPENAI_SSM_PARAM", "/bigpond/openaikey")
        region = os.getenv("AWS_REGION", "ap-southeast-2")
        ssm_client = boto3.client("ssm", region_name=region)
        response = ssm_client.get_parameter(Name=param_name, WithDecryption=True)
        OPENAI_API_KEY = response["Parameter"]["Value"].strip()
        # Expose to any downstream libraries that read from environment
        os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
    except Exception:
        # Leave OPENAI_API_KEY empty; validation below will warn
        pass

# Screen Resolution Configuration
try:
    SCREEN_WIDTH = int(os.getenv("SCREEN_WIDTH") or os.getenv("screen_width") or "1920")
except Exception:
    SCREEN_WIDTH = 1920
try:
    SCREEN_HEIGHT = int(os.getenv("SCREEN_HEIGHT") or os.getenv("screen_height") or "1080")
except Exception:
    SCREEN_HEIGHT = 1080

# Vision generation settings
try:
    OPENAI_VISION_TEMPERATURE = float(os.getenv("OPENAI_VISION_TEMPERATURE", "0.0"))
except Exception:
    OPENAI_VISION_TEMPERATURE = 0.0

# Coordinate Transformation Settings
FIX_INVERTED_X_COORDINATES = os.getenv("FIX_INVERTED_X_COORDINATES", "true").lower() == "true"
Y_CLICK_OFFSET = int(os.getenv("Y_CLICK_OFFSET", "0"))  # Additional pixels to add to y before clicking

# Grid-clicking configuration
USE_GRID_CLICKING = os.getenv("USE_GRID_CLICKING", "true").lower() == "true"
# Smaller grid for finer targeting (A..X by 1..16 yields 24x16)
GRID_COLS = int(os.getenv("GRID_COLS", "48"))
GRID_ROWS = int(os.getenv("GRID_ROWS", "48"))
# Column label style on the rendered grid overlay: 'alpha' | 'numeric' | 'both'
GRID_COL_LABEL_STYLE = os.getenv("GRID_COL_LABEL_STYLE", "numeric").strip().lower()
# Where to draw column labels: 'top' | 'bottom' | 'both'
GRID_COL_LABEL_POSITIONS = os.getenv("GRID_COL_LABEL_POSITIONS", "both").strip().lower()
# Reserve dedicated header bands (top/bottom/left) for labels so they are not part of the grid cells
GRID_USE_HEADER_BANDS = os.getenv("GRID_USE_HEADER_BANDS", "true").strip().lower() == "true"
"""
If true, draw an in-cell label at the center of every grid cell (e.g., 'AA27').
This allows the model to simply read the large, high-contrast label that lies
inside the same cell as the target substring, instead of inferring from headers.
"""
GRID_IN_CELL_LABELS = os.getenv("GRID_IN_CELL_LABELS", "true").strip().lower() == "true"

# External/simple grid renderer selection
# 'internal' -> use built-in overlay
# 'alpha_numeric' -> use add_grid.add_alpha_numeric_grid_to_image
GRID_RENDERER = os.getenv("GRID_RENDERER", "internal").strip().lower()

# Parameters for alpha_numeric renderer
try:
    GRID_ALPHA_CELL_SIZE = int(os.getenv("GRID_CELL_SIZE", "50"))
except Exception:
    GRID_ALPHA_CELL_SIZE = 50
try:
    GRID_TEXT_OPACITY = int(os.getenv("GRID_TEXT_OPACITY", "180"))
except Exception:
    GRID_TEXT_OPACITY = 180
try:
    GRID_TEXT_OFFSET_X = int(os.getenv("GRID_TEXT_OFFSET_X", "5"))
except Exception:
    GRID_TEXT_OFFSET_X = 5
try:
    GRID_ALPHA_FONT_SIZE = int(os.getenv("GRID_ALPHA_FONT_SIZE", str(GRID_LABEL_FONT_SIZE)))
except Exception:
    GRID_ALPHA_FONT_SIZE = GRID_LABEL_FONT_SIZE

# Transparency for alpha-numeric renderer tile fill (0..255). 0 disables tile fill.
try:
    GRID_ALPHA_TILE_ALPHA = int(os.getenv("GRID_ALPHA_TILE_ALPHA", "64"))
except Exception:
    GRID_ALPHA_TILE_ALPHA = 64

# Click offset within a cell when model provides cell_position
try:
    GRID_CELL_OFFSET_FRACTION = float(os.getenv("GRID_CELL_OFFSET_FRACTION", "0.33"))
except Exception:
    GRID_CELL_OFFSET_FRACTION = 0.33
GRID_USE_CELL_POSITION = os.getenv("GRID_USE_CELL_POSITION", "false").strip().lower() == "true"

# Prompt mode for grid finding: 'minimal' -> model returns only grid_id; 'extended' -> also return box and coords
GRID_PROMPT_MODE = os.getenv("GRID_PROMPT_MODE", "minimal").strip().lower()

# Grid-click behavior
# If true, ignore model-provided coordinates and compute click purely from grid
GRID_DISABLE_COORDS = os.getenv("GRID_DISABLE_COORDS", "true").lower() == "true"
# How to choose the column to click when grid is provided:
# 'grid' -> use the model's grid column as-is
# 'center' -> force the column to the center column
# 'label' -> force to a specific column label (see GRID_CLICK_COLUMN_LABEL)
GRID_CLICK_COLUMN = os.getenv("GRID_CLICK_COLUMN", "grid").strip().lower()
GRID_CLICK_COLUMN_LABEL = os.getenv("GRID_CLICK_COLUMN_LABEL", "AA").strip().upper()

# Column derivation when a box is provided in response:
# 'box_center' -> compute column from the center x of the substring box (recommended)
# 'grid' -> trust the model-provided grid column only
# 'coords' -> compute from raw coordinates when present
GRID_COL_SOURCE = os.getenv("GRID_COL_SOURCE", "box_center").strip().lower()

# How to choose the row to click when grid/box are provided:
# 'grid' -> use the model's grid row as-is (exactly the returned grid_id)
# 'box_top' -> derive from the top edge of the returned box (chooses the top row on overlaps)
GRID_ROW_SOURCE = os.getenv("GRID_ROW_SOURCE", "box_top").strip().lower()

# Verification: if true and a substring box is provided in the model response,
# recompute grid_row/grid_column from the box and prefer those over the model's
# provided grid indices when they disagree.
GRID_VERIFY_FROM_BOX = os.getenv("GRID_VERIFY_FROM_BOX", "true").strip().lower() == "true"

# Feature flags / app-based enablement
# Application IDs for which the subplaylist button should be shown (and labeled "Get Support Docs").
# Configure via env var SUPPORTED_SUBPLAYLIST_APP_IDS as comma-separated ints, e.g. "6,10".
def _parse_int_list_env(key: str, default_list: list[int]) -> list[int]:
    try:
        raw = os.getenv(key, None)
        if not raw:
            return default_list
        parts = [p.strip() for p in raw.split(',') if p.strip()]
        vals: list[int] = []
        for p in parts:
            try:
                vals.append(int(p))
            except Exception:
                continue
        return vals or default_list
    except Exception:
        return default_list

SUPPORTED_SUBPLAYLIST_APP_IDS: list[int] = _parse_int_list_env("SUPPORTED_SUBPLAYLIST_APP_IDS", [6])

# Subplaylist target playlist id (the ID of the playlist to call inline)
# Defaults: 61 for local dev, 10 for non-local. Can be overridden via env vars:
#  - SUBPLAYLIST_LOCAL_ID
#  - SUBPLAYLIST_REMOTE_ID
#  - SUBPLAYLIST_TARGET_PLAYLIST_ID (takes precedence over both)
def _parse_int_env(key: str, default_val: int) -> int:
    try:
        raw = os.getenv(key, None)
        if raw is None or str(raw).strip() == "":
            return default_val
        return int(str(raw).strip())
    except Exception:
        return default_val

SUBPLAYLIST_LOCAL_ID = _parse_int_env("SUBPLAYLIST_LOCAL_ID", 61)
SUBPLAYLIST_REMOTE_ID = _parse_int_env("SUBPLAYLIST_REMOTE_ID", 10)
SUBPLAYLIST_TARGET_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_TARGET_PLAYLIST_ID",
    SUBPLAYLIST_LOCAL_ID if LOCAL_DEV else SUBPLAYLIST_REMOTE_ID,
)

# Labels to search for before adding a subplaylist action
# We will attempt in order using Rekognition; first match will be clicked.
def _parse_str_list_env(key: str, default_list: list[str]) -> list[str]:
    try:
        raw = os.getenv(key, None)
        if not raw:
            return default_list
        parts = [p.strip() for p in raw.split(',') if p.strip()]
        return parts or default_list
    except Exception:
        return default_list

ATTACH_FILES_LABELS: list[str] = _parse_str_list_env(
    "ATTACH_FILES_LABELS",
    ["Attach files", "Attatch files", "Files"],
)

# Labels for per-file open action inside the attach-files dialog
VIEW_FILE_LABELS: list[str] = _parse_str_list_env(
    "VIEW_FILE_LABELS",
    ["View"],
)

# Subplaylist to run for each file after clicking "View"
SUBPLAYLIST_VIEW_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_VIEW_PLAYLIST_ID",
    58,
)

# Playlist selection by file count in the attach-files dialog
# Defaults all to 58 for now; override via environment as needed
SUBPLAYLIST_FILES_1_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_FILES_1_PLAYLIST_ID",
    58,
)
SUBPLAYLIST_FILES_2_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_FILES_2_PLAYLIST_ID",
    59,
)
SUBPLAYLIST_FILES_3PLUS_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_FILES_3PLUS_PLAYLIST_ID",
    58,
)

# Fallback playlist when no downloadable/viewable files are present
SUBPLAYLIST_NO_FILES_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_NO_FILES_PLAYLIST_ID",
    61,
)

# Post-fallback playlist selection by file count (after running SUBPLAYLIST_NO_FILES_PLAYLIST_ID)
SUBPLAYLIST_FILES_FALLBACK_1_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_FILES_FALLBACK_1_PLAYLIST_ID",
    62,
)
SUBPLAYLIST_FILES_FALLBACK_2_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_FILES_FALLBACK_2_PLAYLIST_ID",
    63,
)
SUBPLAYLIST_FILES_FALLBACK_3PLUS_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_FILES_FALLBACK_3PLUS_PLAYLIST_ID",
    62,
)

# No-dialog playlists (when dialog is not open after fallback)
SUBPLAYLIST_NO_DIALOG_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_NO_DIALOG_PLAYLIST_ID",
    0,
)
SUBPLAYLIST_NO_DIALOG_1_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_NO_DIALOG_1_PLAYLIST_ID",
    0,
)
SUBPLAYLIST_NO_DIALOG_2_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_NO_DIALOG_2_PLAYLIST_ID",
    0,
)
SUBPLAYLIST_NO_DIALOG_3PLUS_PLAYLIST_ID = _parse_int_env(
    "SUBPLAYLIST_NO_DIALOG_3PLUS_PLAYLIST_ID",
    0,
)

# Batch Deposit pre-check (Rekognition) configuration
# If the phrase is detected on screen BEFORE checking attachments,
# the app will run the configured playlist id instead and stop the attachments flow.
try:
    BATCH_DEPOSIT_PHRASE = os.getenv("BATCH_DEPOSIT_PHRASE", "Transaction: Batch Deposit").strip()
except Exception:
    BATCH_DEPOSIT_PHRASE = "Transaction: Batch Deposit"
BATCH_DEPOSIT_PLAYLIST_ID = _parse_int_env("BATCH_DEPOSIT_PLAYLIST_ID", 0)
# Enable/disable the pre-check globally
BATCH_DEPOSIT_PRECHECK_ENABLED = os.getenv("BATCH_DEPOSIT_PRECHECK_ENABLED", "true").strip().lower() == "true"

# Payment pre-check (Rekognition) configuration
try:
    PAYMENT_PRECHECK_ENABLED = os.getenv("PAYMENT_PRECHECK_ENABLED", "true").strip().lower() == "true"
except Exception:
    PAYMENT_PRECHECK_ENABLED = True
try:
    PAYMENT_PHRASE = os.getenv("PAYMENT_PHRASE", "Transaction: Payment").strip()
except Exception:
    PAYMENT_PHRASE = "Transaction: Payment"
PAYMENT_PLAYLIST_ID = _parse_int_env("PAYMENT_PLAYLIST_ID", 0)
try:
    SPEND_MONEY_PHRASE = os.getenv("SPEND_MONEY_PHRASE", "Transaction: Spend Money").strip()
except Exception:
    SPEND_MONEY_PHRASE = "Transaction: Spend Money"

# Timing for count-based subplaylists (non-View flow)
try:
    FILES_BEFORE_SUBPLAYLIST_DELAY_SEC = float(os.getenv("FILES_BEFORE_SUBPLAYLIST_DELAY_SEC", "0.8"))
except Exception:
    FILES_BEFORE_SUBPLAYLIST_DELAY_SEC = 0.8
try:
    FILES_AFTER_SUBPLAYLIST_DELAY_SEC = float(os.getenv("FILES_AFTER_SUBPLAYLIST_DELAY_SEC", "0.8"))
except Exception:
    FILES_AFTER_SUBPLAYLIST_DELAY_SEC = 0.8
try:
    FILES_SUBPLAYLIST_MIN_WAIT_BETWEEN_ACTIONS = float(os.getenv("FILES_SUBPLAYLIST_MIN_WAIT_BETWEEN_ACTIONS", "1.0"))
except Exception:
    FILES_SUBPLAYLIST_MIN_WAIT_BETWEEN_ACTIONS = 1.0

# Re-check delays after fallbacks/no-dialog initial clicks
try:
    FILES_POST_FALLBACK_RECHECK_DELAY_SEC = float(os.getenv("FILES_POST_FALLBACK_RECHECK_DELAY_SEC", "0.8"))
except Exception:
    FILES_POST_FALLBACK_RECHECK_DELAY_SEC = 0.8
try:
    FILES_POST_NODIALOG_RECHECK_DELAY_SEC = float(os.getenv("FILES_POST_NODIALOG_RECHECK_DELAY_SEC", "0.8"))
except Exception:
    FILES_POST_NODIALOG_RECHECK_DELAY_SEC = 0.8

# Minimum confidence required for clicking the exact word 'View' (WORD-level)
try:
    VIEW_MIN_CONFIDENCE = float(os.getenv("VIEW_MIN_CONFIDENCE", "90.0"))
except Exception:
    VIEW_MIN_CONFIDENCE = 90.0

# Timing for per-file subplaylist execution
try:
    VIEW_BEFORE_SUBPLAYLIST_DELAY_SEC = float(os.getenv("VIEW_BEFORE_SUBPLAYLIST_DELAY_SEC", "0.5"))
except Exception:
    VIEW_BEFORE_SUBPLAYLIST_DELAY_SEC = 0.5
try:
    VIEW_AFTER_SUBPLAYLIST_DELAY_SEC = float(os.getenv("VIEW_AFTER_SUBPLAYLIST_DELAY_SEC", "0.5"))
except Exception:
    VIEW_AFTER_SUBPLAYLIST_DELAY_SEC = 0.5

# Validate OpenAI API key
if not OPENAI_API_KEY:
    print("⚠️  WARNING: OPENAI_API_KEY environment variable not set!")
    print("   Please set your OpenAI API key in your environment variables.")
    print("   Example: export OPENAI_API_KEY='your-api-key-here'")
    print("   Or create a .env file with: OPENAI_API_KEY=your-api-key-here")
    print("   Note: Using GPT-4 Vision (gpt-4o) model for image analysis")
    print(f"   Screen Resolution: {SCREEN_WIDTH}x{SCREEN_HEIGHT}")
else:
    # Basic validation of API key format
    if not OPENAI_API_KEY.startswith(('sk-', 'sk-proj-')):
        print("⚠️  WARNING: OPENAI_API_KEY format appears invalid!")
        print("   OpenAI API keys should start with 'sk-' or 'sk-proj-'")
    else:
        print("✅ OpenAI API key loaded successfully (GPT-4 Vision model)")
        print(f"✅ Screen Resolution: {SCREEN_WIDTH}x{SCREEN_HEIGHT}")

# Special key mapping for pynput to pyautogui
SPECIAL_KEY_MAP = {
    'Key.enter': 'enter',
    'Key.caps_lock': 'capslock',
    'Key.tab': 'tab',
    'Key.shift': 'shift',
    'Key.shift_r': 'shift',
    'Key.ctrl_l': 'ctrl',
    'Key.ctrl_r': 'ctrl',
    'Key.alt_l': 'alt',
    'Key.alt_r': 'alt',
    'Key.esc': 'esc',
    'Key.backspace': 'backspace',
    'Key.space': 'space',
    'Key.delete': 'delete',
    'Key.up': 'up',
    'Key.down': 'down',
    'Key.left': 'left',
    'Key.right': 'right',
}

# Timing
AUTO_EXTRACTOR_CHECK_INTERVAL = 30  # seconds (slower processing)
UI_UPDATE_DELAY = 2  # seconds (more time for UI updates)  
PLAYBACK_STATUS_CHECK_INTERVAL = 5  # seconds (less frequent status checks)

# Chrome Downloads Manager Configuration
CHROME_DOWNLOADS_CHECK_INTERVAL = 5  # seconds (check every 5 seconds)
CHROME_DOWNLOADS_FOLDER = os.path.expanduser("~/Downloads")  # Default downloads folder
CHROME_DOWNLOADS_S3_BUCKET = os.getenv("CHROME_DOWNLOADS_S3_BUCKET", "auditwhizz-chrome-downloads")
CHROME_DOWNLOADS_S3_PREFIX = "chrome_downloads/"
AWS_REGION='ap-southeast-2'

# Coordinate search engine selection
# If true, use AWS Rekognition (OCR) to find coordinates for search instead of OpenAI
USE_AWS_REKOGNITION_FOR_SEARCH = os.getenv("USE_AWS_REKOGNITION_FOR_SEARCH", "false").strip().lower() == "true"
# Rekognition coordinate handling (defaults: preserve raw Rekognition center point)
REKOGNITION_APPLY_TRANSFORM = os.getenv("REKOGNITION_APPLY_TRANSFORM", "false").strip().lower() == "true"
REKOGNITION_APPLY_DISPLAY_SCALE = os.getenv("REKOGNITION_APPLY_DISPLAY_SCALE", "false").strip().lower() == "true"
REKOGNITION_APPLY_Y_OFFSET = os.getenv("REKOGNITION_APPLY_Y_OFFSET", "false").strip().lower() == "true"

# Rekognition tiling configuration
# Always enable tiling for Rekognition searches
REKOGNITION_USE_TILING = True
# Default to a fixed 1x3 grid when not provided via env
REKOGNITION_TILE_GRID = (os.getenv("REKOGNITION_TILE_GRID", "1x3").strip().lower() or "1x3")
try:
    REKOGNITION_TILE_OVERLAP = float(os.getenv("REKOGNITION_TILE_OVERLAP", "0.08"))
except Exception:
    REKOGNITION_TILE_OVERLAP = 0.08
try:
    REKOGNITION_UPSCALE_FACTOR = float(os.getenv("REKOGNITION_UPSCALE_FACTOR", "1.0"))
except Exception:
    REKOGNITION_UPSCALE_FACTOR = 1.0
REKOGNITION_TILING_DEBUG_SAVE_ALL = os.getenv("REKOGNITION_TILING_DEBUG_SAVE_ALL", "false").strip().lower() == "true"

# De-duplicate Rekognition clicks with same label by ignoring previously clicked points
REKOGNITION_DEDUPLICATE_POINTS = os.getenv("REKOGNITION_DEDUPLICATE_POINTS", "true").strip().lower() == "true"
try:
    REKOGNITION_DEDUP_RADIUS_PX = int(os.getenv("REKOGNITION_DEDUP_RADIUS_PX", "28"))
except Exception:
    REKOGNITION_DEDUP_RADIUS_PX = 28

# OpenAI Analyzer Configuration
OPENAI_ANALYZER_S3_BUCKET = os.getenv("OPENAI_ANALYZER_S3_BUCKET", "auditwhizz-supporting-documents")
OPENAI_ANALYZER_S3_PREFIX = "supporting_documents/"
POST_CLICK_WAIT_TIME = 15  # seconds to wait after each click (configurable)

# Screenshot upload configuration
# Separate bucket/prefix for generic screenshots captured by the app
SCREENSHOT_S3_BUCKET = os.getenv("SCREENSHOT_S3_BUCKET", OPENAI_ANALYZER_S3_BUCKET)
SCREENSHOT_S3_PREFIX = os.getenv("SCREENSHOT_S3_PREFIX", "screenshots/")

# Session artifact archival (logs + screenshots) configuration
SESSION_LOGS_S3_BUCKET = os.getenv("SESSION_LOGS_S3_BUCKET", "big-pond-autoclicker-logs")
SESSION_LOGS_S3_PREFIX = os.getenv("SESSION_LOGS_S3_PREFIX", "sessions/")

# Screenshot behavior
# If true, only capture the browser window client area and do not fall back to full-screen
BROWSER_ONLY_SCREENSHOT = os.getenv("BROWSER_ONLY_SCREENSHOT", "true").lower() == "true"
# If true, attempt a full-height scrolling capture of the browser page for action screenshots (playback 'screenshot' action)
# Default: enabled per request
FULL_PAGE_BROWSER_SCREENSHOT = os.getenv("FULL_PAGE_BROWSER_SCREENSHOT", "true").lower() == "true"
# If true, force the playback screenshot to be a full-screen grab and skip all other methods
FORCE_FULLSCREEN_SCREENSHOT = os.getenv("FORCE_FULLSCREEN_SCREENSHOT", "false").strip().lower() == "true"
# If true, keep local screenshot files for debugging (do not delete after upload or at playlist end)
KEEP_SCREENSHOTS_FOR_DEBUG = os.getenv("KEEP_SCREENSHOTS_FOR_DEBUG", "false").strip().lower() == "true"
# Which monitor to capture for fullscreen screenshots: -1 = active window's monitor, 1..N = specific monitor index, 0/other = primary
try:
    SCREENSHOT_MONITOR_INDEX = int(os.getenv("SCREENSHOT_MONITOR_INDEX", "-1"))
except Exception:
    SCREENSHOT_MONITOR_INDEX = -1
# Optional title filter used by full-page scroll-and-stitch capture; default to Chrome
FULLPAGE_WINDOW_TITLE_CONTAINS = os.getenv("FULLPAGE_WINDOW_TITLE_CONTAINS", "Chrome")
# Fine-tuning parameters for the v2 scroll-and-stitch capture
# Defaults now set to 0 so no cropping occurs unless explicitly configured
try:
    FULLPAGE_CONTENT_TOP_OFFSET = int(os.getenv("FULLPAGE_CONTENT_TOP_OFFSET", "0"))
except Exception:
    FULLPAGE_CONTENT_TOP_OFFSET = 0
try:
    FULLPAGE_CONTENT_BOTTOM_OFFSET = int(os.getenv("FULLPAGE_CONTENT_BOTTOM_OFFSET", "0"))
except Exception:
    FULLPAGE_CONTENT_BOTTOM_OFFSET = 0
try:
    FULLPAGE_OVERLAP_PX = int(os.getenv("FULLPAGE_OVERLAP_PX", "160"))
except Exception:
    FULLPAGE_OVERLAP_PX = 160
try:
    FULLPAGE_SCROLL_PX = int(os.getenv("FULLPAGE_SCROLL_PX", "600"))
except Exception:
    FULLPAGE_SCROLL_PX = 600
try:
    FULLPAGE_SCROLL_PAUSE = float(os.getenv("FULLPAGE_SCROLL_PAUSE", "1.0"))
except Exception:
    FULLPAGE_SCROLL_PAUSE = 0.2
try:
    FULLPAGE_MAX_SHOTS = int(os.getenv("FULLPAGE_MAX_SHOTS", "30"))
except Exception:
    FULLPAGE_MAX_SHOTS = 30
USE_PAGEDOWN_FOR_FULLPAGE = os.getenv("USE_PAGEDOWN_FOR_FULLPAGE", "true").strip().lower() == "true"

# Pre-capture delay (seconds) before taking analysis screenshots to let UI settle
try:
    SCREENSHOT_PRE_DELAY_SEC = float(os.getenv("SCREENSHOT_PRE_DELAY_SEC", "5.0"))
except Exception:
    SCREENSHOT_PRE_DELAY_SEC = 5.0

# Rekognition image settings
REKOGNITION_IMAGE_FORMAT = os.getenv("REKOGNITION_IMAGE_FORMAT", "PNG").strip().upper()  # PNG|JPEG
try:
    REKOGNITION_JPEG_QUALITY = int(os.getenv("REKOGNITION_JPEG_QUALITY", "92"))
except Exception:
    REKOGNITION_JPEG_QUALITY = 92