"""
QuickBooks Supporting Documents flow (skeleton).

This module defines the entry point for the QuickBooks supporting documents
flow. We will implement the steps incrementally.
"""


def _scroll_to_bottom() -> None:
    """Scroll to the bottom of the page using keyboard and wheel fallbacks."""
    try:
        import time as _time
        import pyautogui as _pg
        # Primary: Ctrl+End reaches very bottom in most browsers/apps
        try:
            _pg.hotkey('ctrl', 'end')
            _time.sleep(0.2)
        except Exception:
            pass
        # Secondary: press End as additional nudge
        try:
            _pg.press('end')
            _time.sleep(0.1)
        except Exception:
            pass
        # Fallback: a few strong wheel scroll downs
        try:
            for _ in range(6):
                _pg.scroll(-800)  # negative -> down
                _time.sleep(0.05)
        except Exception:
            pass
    except Exception:
        pass


def _focus_content_region() -> None:
    """Bring focus to the web page by clicking near the screen center."""
    try:
        import pyautogui as _pg
        import time as _time
        try:
            sw, sh = _pg.size()
        except Exception:
            sw, sh = 1920, 1080
        cx = int(max(10, sw // 2))
        cy = int(max(10, sh // 2))
        _pg.moveTo(cx, cy)
        _pg.click()
        _time.sleep(0.1)
    except Exception:
        pass

def play_supporting_docs(app) -> None:
    """Entry point for the QuickBooks supporting documents flow."""
    # Step 1: Scroll to the bottom where attachments are located
    try:
        if hasattr(app, "status_var"):
            app.status_var.set("QuickBooks: scrolling to bottom...")
    except Exception:
        pass
    # Ensure the web content has focus before scrolling
    _focus_content_region()
    _scroll_to_bottom()
    # Allow UI to settle after scroll
    try:
        import time as _time
        _time.sleep(2.0)
    except Exception:
        pass

    # Step 2: Find attachment links under the "Attachments" section using OpenAI
    try:
        if hasattr(app, "status_var"):
            app.status_var.set("QuickBooks: analyzing for attachment links...")
    except Exception:
        pass

    # Acquire analyzer
    try:
        analyzer = getattr(app, 'screenshot_manager', None)
        analyzer = getattr(analyzer, 'openai_analyzer', None)
        if analyzer is None:
            if hasattr(app, 'status_var'):
                app.status_var.set("Analyzer unavailable")
            return
    except Exception:
        try:
            if hasattr(app, 'status_var'):
                app.status_var.set("Analyzer unavailable")
        except Exception:
            pass
        return

    # Capture screenshot (ensure focus, then small delay to allow UI settle after scroll)
    try:
        import time as _time
        # Ensure the web content has focus before capture
        _focus_content_region()
        _time.sleep(0.4)
        screenshot_path = analyzer.capture_full_resolution_screenshot()
        if not screenshot_path:
            if hasattr(app, 'status_var'):
                app.status_var.set("Failed to capture screenshot")
            return
    except Exception:
        try:
            if hasattr(app, 'status_var'):
                app.status_var.set("Failed to capture screenshot")
        except Exception:
            pass
        return

    # Build QB-specific "Attachments" links prompt
    def _qb_attachments_links_prompt(width: int, height: int) -> str:
        sw = int(width); sh = int(height)
        _tmpl = (
            """
                Analyze this QuickBooks screenshot and identify ONLY supporting document links that appear
                under the 'Attachments' section/heading (also consider common misspellings: 'Attachements', 'Attatchements').

                Look for:
                - The clickable file names (e.g., Invoice 1010.pdf) in the list under Attachments
                - Download/View links or buttons for receipts, PDFs, or supporting documents in that list only
                - File attachment icons (paperclip, document, PDF icons) for those files

                Return ONLY a JSON array with this exact format:
                [
                    {
                        "type": "supporting_document_link",
                        "description": "brief description of what the link provides",
                        "link_words": "the exact visible text (verbatim)",
                        "coordinates": [x, y],
                        "confidence": 0.95,
                        "button": true
                    }
                ]

                Rules:
                - Include links ONLY if they are visually under the Attachments heading/label
                - link_words MUST be the exact clickable text; for icon-only, set link_words to ""
                - button: true for buttons/icons; false for plain text links
                - Coordinates are pixel center of the clickable element (0-__XMAX__ for x, 0-__YMAX__ for y)
                - EXCLUDE anything not part of the file list, including: "Add attachment", "Select All",
                  "Attach to email", remove "x" icons, size labels (e.g., "15KB"), and section helper text
                - Return valid JSON only, no extra commentary
                - This screenshot is __SW__x__SH__ pixels
            """
        )
        return (
            _tmpl
            .replace("__XMAX__", str(sw - 1))
            .replace("__YMAX__", str(sh - 1))
            .replace("__SW__", str(sw))
            .replace("__SH__", str(sh))
        )

    # Prepare prompt and image
    try:
        sw, sh = analyzer._get_screen_size()
    except Exception:
        sw, sh = 1920, 1080

    prompt = _qb_attachments_links_prompt(sw, sh)
    
    try:
        import base64 as _b64
        with open(screenshot_path, 'rb') as _f:
            _img_b = _f.read()
        _img_b64 = _b64.b64encode(_img_b).decode('utf-8')
        image_url = f"data:image/png;base64,{_img_b64}"
    except Exception:
        if hasattr(app, 'status_var'):
            app.status_var.set("Failed to prepare screenshot")
        return

    # Call OpenAI vision
    try:
        try:
            from .constants import OPENAI_VISION_TEMPERATURE
        except Exception:
            OPENAI_VISION_TEMPERATURE = 0.0

        content = analyzer._post_vision(
            prompt,
            image_url,
            max_tokens=1600,
            temperature=float(OPENAI_VISION_TEMPERATURE),
        )
    except Exception:
        try:
            if hasattr(app, 'status_var'):
                app.status_var.set("Analyze failed")
        except Exception:
            pass
        return

    # Parse JSON array from response
    try:
        import json as _json
        _start = content.find('['); _end = content.rfind(']') + 1
        if _start != -1 and _end != -1:
            _json_str = content[_start:_end]
            _links = _json.loads(_json_str)
        else:
            _links = []
    except Exception:
        _links = []

    # Validate and normalize
    validated_links = []
    for link in (_links or []):
        if not isinstance(link, dict):
            continue
        if 'link_words' not in link:
            try:
                desc = str(link.get('description') or '').strip()
                link['link_words'] = desc
            except Exception:
                link['link_words'] = ''
        if 'button' not in link:
            link['button'] = False
        try:
            coords = link.get('coordinates', [])
            if analyzer._validate_coordinates(coords):
                validated_links.append(link)
        except Exception:
            continue

    # Filter out known non-file entries that should not be considered supporting docs
    try:
        _exclude_words = {
            'add attachment', 'select all', 'attach to email', 'max file size', 'size', 'kb', 'mb',
        }
        _filtered_links = []
        for _lnk in validated_links:
            try:
                _w = str(_lnk.get('link_words') or '').strip().lower()
            except Exception:
                _w = ''
            # Exclude exact helper/control texts; allow filenames like *.pdf, *.jpg, etc.
            if any(word in _w for word in _exclude_words):
                continue
            _filtered_links.append(_lnk)
        validated_links = _filtered_links
    except Exception:
        pass

    # Expose for subsequent steps and decide continuation
    try:
        setattr(app, '_qb_attachment_links', validated_links)
    except Exception:
        pass

    if not validated_links:
        try:
            if hasattr(app, 'status_var'):
                app.status_var.set("No attachment links found")
        except Exception:
            pass
        return

    # Click sequentially with a short wait between, no screenshots or extra actions
    try:
        if hasattr(app, 'status_var'):
            app.status_var.set(f"Clicking {len(validated_links)} attachment link(s) sequentially...")
    except Exception:
        pass

    # Determine wait between clicks
    try:
        import os as _os
        import time as _time
        try:
            wait_between = float(_os.getenv('QB_CLICK_WAIT_SEC', '2.0'))
        except Exception:
            wait_between = 2.0
    except Exception:
        # Fallback if imports fail
        wait_between = 2.0
        import time as _time

    # Track clicked coordinates to avoid re-clicking the same location
    clicked_points = []  # list of (x,y)
    try:
        dedup_radius = float(_os.getenv('QB_DEDUP_RADIUS_PX', '28'))
    except Exception:
        dedup_radius = 28.0

    def _is_near_clicked(pt) -> bool:
        try:
            if not isinstance(pt, (list, tuple)) or len(pt) != 2:
                return False
            px, py = float(pt[0]), float(pt[1])
            for (cx, cy) in clicked_points:
                dx = px - cx; dy = py - cy
                if (dx*dx + dy*dy) ** 0.5 <= dedup_radius:
                    return True
        except Exception:
            return False
        return False

    # Prepare Rekognition client and PIL image once
    try:
        from PIL import Image as _QBImg
        import boto3 as _b3
        from .rekognition_tiler import find_text_coordinates_tiled as _qb_tiler
        from .constants import AWS_REGION as _QB_AWS_REGION
        _qb_img = _QBImg.open(screenshot_path).convert('RGB')
        _qb_rk = _b3.client('rekognition', region_name=_QB_AWS_REGION)
    except Exception:
        _qb_img = None
        _qb_rk = None
        _qb_tiler = None

    # Tiler parameters
    try:
        _upscale = float(_os.getenv('QB_REKOGNITION_UPSCALE', '2.0'))
    except Exception:
        _upscale = 2.0
    try:
        _overlap = float(_os.getenv('QB_REKOGNITION_TILE_OVERLAP', '0.10'))
    except Exception:
        _overlap = 0.10
    _debug_dir = None
    try:
        if _os.getenv('QB_REKOG_DEBUG', '0') in ('1', 'true', 'True'):
            from pathlib import Path as _Path
            import time as _t
            _debug_dir = _Path('logs') / 'openai_debug' / f"rekognition_{int(_t.time()*1000)}"
            _debug_dir.mkdir(parents=True, exist_ok=True)
            _debug_dir = str(_debug_dir)
    except Exception:
        _debug_dir = None

    for idx, link in enumerate(validated_links, start=1):
        # Always rely ONLY on Rekognition for clickable coordinates
        # Clear any pre-existing (OpenAI) coordinates to avoid fallback
        try:
            if 'coordinates' in link:
                link['coordinates'] = None
            if '_coords_are_screen' in link:
                del link['_coords_are_screen']
        except Exception:
            pass

        # Prefer Rekognition-derived coordinates using the exact link words
        try:
            lw = str(link.get('link_words') or '').strip()
        except Exception:
            lw = ''
        coords = None
        if lw and _qb_img is not None and _qb_rk is not None and _qb_tiler is not None:
            try:
                coords = _qb_tiler(
                    _qb_rk,
                    _qb_img,
                    query=lw,
                    is_regex=False,
                    upscale=_upscale,
                    overlap_frac=_overlap,
                    debug_dir=_debug_dir,
                    require_include=True,
                    exclude_points=clicked_points,
                    exclude_radius=int(dedup_radius),
                )
            except Exception:
                coords = None
        # If Rekognition did not find coordinates, skip this link
        if not (isinstance(coords, (list, tuple)) and len(coords) == 2):
            try:
                if hasattr(app, 'status_var'):
                    app.status_var.set(f"Skipping attachment {idx}: Rekognition did not locate '{(lw or 'link')}'")
            except Exception:
                pass
            continue
        # Set screen-space coords from Rekognition result
        try:
            link['coordinates'] = [int(coords[0]), int(coords[1])]
            link['_coords_are_screen'] = True  # signal no transform needed
        except Exception:
            pass

        # Skip if this link's coordinates are near a previously clicked point
        try:
            _coords = link.get('coordinates')
            if _is_near_clicked(_coords):
                continue
        except Exception:
            pass

        try:
            if hasattr(app, 'status_var'):
                app.status_var.set(f"Clicking attachment {idx}/{len(validated_links)}...")
        except Exception:
            pass

        try:
            _res = analyzer._click_link(link)
            try:
                if isinstance(_res, dict) and _res.get('success') and isinstance(_res.get('coordinates'), (list, tuple)) and len(_res.get('coordinates')) == 2:
                    clicked_points.append((int(_res['coordinates'][0]), int(_res['coordinates'][1])))
                else:
                    clicked_points.append((int(coords[0]), int(coords[1])))
            except Exception:
                pass
        except Exception:
            pass

        # After click: wait 2s, run subplaylist id=100, wait 1s, then run save dialog once
        try:
            _time.sleep(2.0)
        except Exception:
            pass
        try:
            from .playback import PlaybackManager as _QBPlayback
            mgr = _QBPlayback(app)
            # Resolve playlist id from env with safe fallback to 100
            try:
                env_val = _os.getenv('QUICKBOOKS_DOWNLOAD_ICON_CLICK_PLAYLIST') or _os.getenv('QUCKBOOKS_DOWNLOAD_ICON_CLICK_PLAYLIST') or ''
                pl_id = int(str(env_val).strip()) if str(env_val).strip() else 100
            except Exception:
                pl_id = 100
            if int(pl_id) > 0:
                # Ensure playback loop semantics so subplaylist actions execute
                try:
                    if hasattr(app, 'status_var') and getattr(app.status_var, 'get', lambda: None)() != 'Paused':
                        app.status_var.set('Playing')
                except Exception:
                    pass
                mgr._execute_playlist_by_id(int(pl_id))
        except Exception:
            pass
        try:
            _time.sleep(0.3)
        except Exception:
            pass
        try:
            from .xero_util.attach_files_dialog_utils import run_save_dialog_once_if_present as _qb_save_once
            _qb_save_once(app)
        except Exception:
            pass

        # Close current document page/tab, then switch back to first tab
        try:
            from .browser_tabs import (
                close_current_tab_via_hotkey as _qb_close_current,
                switch_to_first_tab as _qb_switch_first,
            )
        except Exception:
            _qb_close_current = None; _qb_switch_first = None
        try:
            if callable(_qb_close_current):
                _qb_close_current()
        except Exception:
            pass
        # try:
        #     if callable(_qb_switch_first):
        #         _qb_switch_first()
        # except Exception:
        #     pass

        try:
            _time.sleep(wait_between)
        except Exception:
            pass

    try:
        if hasattr(app, 'status_var'):
            app.status_var.set("Attachment link flow complete")
    except Exception:
        pass
    return
