"""
NotebookLM authentication using undetected-chromedriver with Xvfb for headless operation.
This bypasses Google's bot detection and allows proper session creation on a server.
"""
import os
import time
import json
import subprocess
from flask import current_app


def start_xvfb():
    """Start Xvfb if not already running."""
    try:
        # Check if Xvfb is already running
        result = subprocess.run(['pgrep', '-f', 'Xvfb'], capture_output=True)
        if result.returncode == 0:
            current_app.logger.info("Xvfb already running")
            return True

        # Start Xvfb on display :99
        xvfb_process = subprocess.Popen(
            ['Xvfb', ':99', '-screen', '0', '1280x720x24', '-ac'],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )

        # Set DISPLAY environment variable
        os.environ['DISPLAY'] = ':99'

        # Wait a bit for Xvfb to start
        time.sleep(2)

        current_app.logger.info("Started Xvfb on display :99")
        return True

    except Exception as e:
        current_app.logger.error(f"Error starting Xvfb: {e}")
        return False


def authenticate_user_notebooklm(storage_path):
    """
    Authenticate to NotebookLM using undetected-chromedriver with Xvfb.

    NOTE: This function runs in headless mode and cannot perform manual login.
    It only validates existing sessions or will fail if no valid session exists.

    For proper authentication, users should:
    1. Manually create a session file using Playwright on their local machine
    2. Upload the session file via the admin interface

    This approach:
    1. Starts Xvfb for headless display
    2. Uses undetected-chromedriver to bypass bot detection
    3. Opens a browser window (will run in headless mode with Xvfb)
    4. Validates existing session or fails gracefully

    Args:
        storage_path: Path to save the storage_state.json

    Returns:
        True if successful, False otherwise
    """
    try:
        import undetected_chromedriver as uc
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support.ui import WebDriverWait
        from selenium.webdriver.support import expected_conditions as EC

        os.makedirs(os.path.dirname(storage_path), exist_ok=True)

        # Start Xvfb for headless operation
        start_xvfb()

        # Configure Chrome options for headless operation with Xvfb
        options = uc.ChromeOptions()

        # Run with Xvfb display
        display = os.environ.get('DISPLAY', ':99')

        options.add_argument(f'--display={display}')
        options.add_argument('--headless=new')  # New headless mode
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-dev-shm-usage')
        options.add_argument('--disable-gpu')
        options.add_argument('--disable-software-rasterizer')
        options.add_argument('--disable-dev-shm-usage')
        options.add_argument('--disable-blink-features=AutomationControlled')
        options.add_argument('--disable-infobars')
        options.add_argument('--disable-extensions')
        options.add_argument('--disable-notifications')
        options.add_argument('--window-size=1280x720')

        # Set binary location
        options.binary_location = '/usr/bin/chromium-browser'

        current_app.logger.info(f"Starting undetected Chrome with display {display}...")

        # Create driver
        driver = uc.Chrome(options=options, version_main=None)

        try:
            # Navigate to Google login
            current_app.logger.info("Navigating to Google login...")
            driver.get("https://accounts.google.com/signin")

            # Since we're in headless mode and can't do manual login,
            # we need to use a different approach.
            # For now, let's navigate to NotebookLM and see what happens

            time.sleep(5)

            # Try to navigate to NotebookLM directly
            current_app.logger.info("Navigating to NotebookLM...")
            driver.get("https://notebooklm.google.com/")
            time.sleep(5)

            # Check current URL
            current_url = driver.current_url
            current_app.logger.info(f"Current URL: {current_url}")

            # Check if we're on a page that indicates we need to log in
            if 'accounts.google.com' in current_url or 'ServiceLogin' in current_url:
                current_app.logger.warning("Not logged in - manual login required")
                # In headless mode, we can't do manual login
                # Save whatever cookies we have
                cookies = driver.get_cookies()
                storage_state = {
                    'cookies': [],
                    'origins': []
                }
                for cookie in cookies:
                    storage_state['cookies'].append({
                        'name': cookie['name'],
                        'value': cookie['value'],
                        'domain': cookie['domain'],
                        'path': cookie['path'],
                        'expiry': cookie.get('expiry'),
                        'httpOnly': cookie['httpOnly'],
                        'secure': cookie['secure'],
                        'sameSite': cookie.get('sameSite', 'None')
                    })

                with open(storage_path, 'w') as f:
                    json.dump(storage_state, f, indent=2)

                driver.quit()
                return False

            # If we're on NotebookLM without redirect, check for SID
            cookies = driver.get_cookies()
            cookie_names = [c['name'] for c in cookies]

            has_sid = 'SID' in cookie_names or 'HSID' in cookie_names
            current_app.logger.info(f"Cookie names: {cookie_names[:10]}..., has SID: {has_sid}")

            if has_sid:
                # Save full session state
                storage_state = {
                    'cookies': [],
                    'origins': []
                }

                for cookie in cookies:
                    storage_state['cookies'].append({
                        'name': cookie['name'],
                        'value': cookie['value'],
                        'domain': cookie['domain'],
                        'path': cookie['path'],
                        'expiry': cookie.get('expiry'),
                        'httpOnly': cookie['httpOnly'],
                        'secure': cookie['secure'],
                        'sameSite': cookie.get('sameSite', 'None')
                    })

                # Get localStorage
                try:
                    local_storage = driver.execute_script("return Object.assign({}, localStorage);")
                    if local_storage:
                        storage_state['origins'].append({
                            'origin': 'https://notebooklm.google.com',
                            'localStorage': [{'name': k, 'value': v} for k, v in local_storage.items()]
                        })
                except:
                    pass

                with open(storage_path, 'w') as f:
                    json.dump(storage_state, f, indent=2)

                current_app.logger.info(f"Successfully saved NotebookLM session to {storage_path}")
                driver.quit()
                return True
            else:
                current_app.logger.warning("No SID cookie found - authentication incomplete")
                driver.quit()
                return False

        except Exception as e:
            current_app.logger.error(f"Error during authentication: {e}")
            try:
                driver.quit()
            except:
                pass
            raise

    except Exception as e:
        current_app.logger.error(f"Error in authenticate_user_notebooklm: {e}")
        import traceback
        current_app.logger.error(traceback.format_exc())
        return False


def create_notebook_with_session(storage_path, notebook_name, report_content=""):
    """
    Create a new notebook in NotebookLM using existing session.

    Args:
        storage_path: Path to the session file
        notebook_name: Name for the new notebook
        report_content: Optional content to add to the notebook

    Returns:
        notebook_url: URL of the created notebook, or None if failed
    """
    try:
        import undetected_chromedriver as uc
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support.ui import WebDriverWait
        from selenium.webdriver.common.keys import Keys
        import requests

        # Start Xvfb
        start_xvfb()

        # Validate session first
        if not validate_nlm_session(storage_path):
            current_app.logger.error("Invalid or expired session")
            return None

        options = uc.ChromeOptions()
        display = os.environ.get('DISPLAY', ':99')
        options.add_argument(f'--display={display}')
        options.add_argument('--headless=new')
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-dev-shm-usage')
        options.add_argument('--disable-gpu')
        options.add_argument('--disable-software-rasterizer')
        options.add_argument('--disable-blink-features=AutomationControlled')
        options.add_argument('--window-size=1280x720')
        options.binary_location = '/usr/bin/chromium-browser'

        driver = uc.Chrome(options=options, version_main=None)

        try:
            # Load session
            with open(storage_path, 'r') as f:
                storage = json.load(f)

            # Go to Google first to set domain cookies
            driver.get("https://accounts.google.com")

            for cookie in storage.get('cookies', []):
                try:
                    driver.add_cookie(cookie)
                except Exception as e:
                    current_app.logger.warning(f"Could not add cookie {cookie.get('name')}: {e}")

            # Load localStorage if available
            for origin in storage.get('origins', []):
                if 'localStorage' in origin:
                    driver.get(origin['origin'])
                    for item in origin['localStorage']:
                        try:
                            driver.execute_script(f"localStorage.setItem('{item['name']}', '{item['value']}');")
                        except:
                            pass

            # Navigate to NotebookLM
            current_app.logger.info("Navigating to NotebookLM...")
            driver.get("https://notebooklm.google.com/")
            time.sleep(5)

            current_url = driver.current_url
            current_app.logger.info(f"After loading session, URL: {current_url}")

            # Check if we have SID cookie now
            cookies = driver.get_cookies()
            cookie_names = [c['name'] for c in cookies]
            has_sid = 'SID' in cookie_names or 'HSID' in cookie_names
            current_app.logger.info(f"After reload, cookie names: {cookie_names[:10]}..., has SID: {has_sid}")

            # Try to find and click create button
            try:
                # Wait for page to fully load
                time.sleep(3)

                # Try multiple selectors for the create button
                create_selectors = [
                    "//button[@aria-label and contains(@aria-label, 'Create')]",
                    "//button[.//text()='Create' or .//text()='إنشاء']",
                    "//div[@role='button' and (contains(., 'Create') or contains(., 'إنشاء'))]",
                    "//span[(text()='Create' or text()='إنشاء')]/parent::button",
                    "button[aria-label*='Create']",
                    "//button[contains(@class, 'create')]",
                ]

                button_found = False
                for selector in create_selectors:
                    try:
                        elements = driver.find_elements(By.XPATH, selector)
                        if elements:
                            elements[0].click()
                            current_app.logger.info("Clicked create button")
                            button_found = True
                            time.sleep(2)
                            break
                    except Exception as e:
                        current_app.logger.debug(f"Selector {selector} failed: {e}")
                        continue

                if button_found:
                    # Enter notebook name
                    name_input = None
                    name_selectors = [
                        "//input[@type='text']",
                        "//textarea",
                        "//input[@placeholder and contains(@placeholder, 'notebook')]",
                    ]

                    for selector in name_selectors:
                        try:
                            inputs = driver.find_elements(By.XPATH, selector)
                            if inputs:
                                # Find the main input (usually the first visible one)
                                for inp in inputs:
                                    if inp.is_displayed():
                                        name_input = inp
                                        break
                                if not name_input and inputs:
                                    name_input = inputs[0]
                                break
                        except:
                            continue

                    if name_input:
                        # Clear and type notebook name
                        name_input.clear()
                        name_input.send_keys(notebook_name)
                        time.sleep(1)

                        # Submit to create
                        name_input.send_keys(Keys.RETURN)
                        time.sleep(5)

                        # Get the notebook URL
                        notebook_url = driver.current_url
                        current_app.logger.info(f"Created notebook: {notebook_url}")

                        # Save updated session
                        cookies = driver.get_cookies()
                        storage['cookies'] = [{
                            'name': c['name'],
                            'value': c['value'],
                            'domain': c['domain'],
                            'path': c['path'],
                            'expiry': c.get('expiry'),
                            'httpOnly': c['httpOnly'],
                            'secure': c['secure'],
                            'sameSite': c.get('sameSite', 'None')
                        } for c in cookies]

                        with open(storage_path, 'w') as f:
                            json.dump(storage, f, indent=2)

                        driver.quit()
                        return notebook_url
                    else:
                        current_app.logger.error("Could not find name input field")

                else:
                    current_app.logger.error("Could not find create button")

                # Even if we couldn't create a notebook, save the updated session
                cookies = driver.get_cookies()
                storage['cookies'] = [{
                    'name': c['name'],
                    'value': c['value'],
                    'domain': c['domain'],
                    'path': c['path'],
                    'expiry': c.get('expiry'),
                    'httpOnly': c['httpOnly'],
                    'secure': c['secure'],
                    'sameSite': c.get('sameSite', 'None')
                } for c in cookies]

                with open(storage_path, 'w') as f:
                    json.dump(storage, f, indent=2)

                driver.quit()
                return None

            except Exception as e:
                current_app.logger.error(f"Error creating notebook: {e}")
                import traceback
                current_app.logger.error(traceback.format_exc())

                # Save session before quitting
                try:
                    cookies = driver.get_cookies()
                    storage['cookies'] = [{
                        'name': c['name'],
                        'value': c['value'],
                        'domain': c['domain'],
                        'path': c['path'],
                        'expiry': c.get('expiry'),
                        'httpOnly': c['httpOnly'],
                        'secure': c['secure'],
                        'sameSide': c.get('sameSite', 'None')
                    } for c in cookies]

                    with open(storage_path, 'w') as f:
                        json.dump(storage, f, indent=2)
                except:
                    pass

                driver.quit()
                return None

        except Exception as e:
            current_app.logger.error(f"Error in create_notebook_with_session: {e}")
            import traceback
            current_app.logger.error(traceback.format_exc())
            try:
                driver.quit()
            except:
                pass
            return None

    except Exception as e:
        current_app.logger.error(f"Error setting up driver: {e}")
        import traceback
        current_app.logger.error(traceback.format_exc())
        return None


def validate_nlm_session(storage_path):
    """Check if the stored session contains valid Google session cookies."""
    try:
        if not os.path.exists(storage_path):
            return False

        with open(storage_path, 'r') as f:
            storage = json.load(f)

        cookies = storage.get('cookies', [])
        cookie_names = [c.get('name') for c in cookies]

        has_sid = 'SID' in cookie_names or 'HSID' in cookie_names or 'SSID' in cookie_names

        current_app.logger.info(f"Cookie validation - has SID: {has_sid}, found: {cookie_names[:5] if len(cookie_names) > 5 else cookie_names}")
        return has_sid

    except Exception as e:
        current_app.logger.error(f"Error validating session: {e}")
        return False


def get_nlm_cookies_with_oauth(access_token, storage_path, refresh_token=None):
    """
    Fallback function that tries to get NotebookLM cookies.
    This is called by the existing route but delegates to the new implementation.
    """
    return authenticate_user_notebooklm(storage_path)
