"""
Playwright CRM Login Module
============================

This module provides functionality to automate CRM login using Playwright
and extract session cookies for subsequent API calls.
"""

import asyncio
import logging
from typing import Dict, Optional
from playwright.async_api import async_playwright, Browser, BrowserContext, Page

logger = logging.getLogger(__name__)


class CRMLoginError(Exception):
    """Exception raised for CRM login errors"""
    pass


async def login_to_crm(
    url: str,
    username: str,
    password: str,
    headless: bool = False,
    incognito: bool = False,
    timeout: int = 30000
) -> Dict[str, str]:
    """
    Automate CRM login using Playwright and extract session cookies.

    This function launches a browser, navigates to the CRM login page,
    fills in credentials, waits for successful login, and extracts
    the necessary cookies for API authentication.

    Args:
        url: The CRM base URL (e.g., https://internalcrm.macausjm-glp.com)
        username: CRM username (can include domain like "DOMAIN\\username")
        password: CRM password
        headless: Whether to run browser in headless mode (default: False)
        incognito: Whether to use strict incognito mode with no cache (default: False)
        timeout: Login timeout in milliseconds (default: 30000)

    Returns:
        dict: Dictionary containing:
            - ReqClientId: Session request client ID cookie
            - orgId: Organization ID cookie

    Raises:
        CRMLoginError: If login fails or cookies cannot be extracted

    Example:
        >>> cookies = await login_to_crm(
        ...     "https://internalcrm.macausjm-glp.com",
        ...     "DOMAIN\\\\user.name",
        ...     "password"
        ... )
        >>> print(cookies['ReqClientId'])
    """
    async with async_playwright() as p:
        browser = None
        context = None

        try:
            # Launch browser
            mode_desc = "headless" if headless else "visible"
            if incognito:
                mode_desc += " + incognito"
            logger.info(f"Launching browser ({mode_desc})...")

            # Launch with incognito options if specified
            launch_options = {
                "headless": headless
            }

            if incognito:
                # Use a temporary user data directory that gets deleted after session
                import tempfile
                temp_dir = tempfile.mkdtemp(prefix="playwright_incognito_")
                launch_options["args"] = [
                    f"--user-data-dir={temp_dir}",
                    "--incognito",
                    "--disable-gpu",
                    "--no-sandbox"
                ]

            browser = await p.chromium.launch(**launch_options)

            # Create browser context with incognito settings
            context_options = {
                "viewport": {"width": 1280, "height": 720},
                "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
            }

            if incognito:
                # Strict incognito: disable cache and storage
                context_options.update({
                    "ignore_http_se_errors": True,
                    "java_script_enabled": True,
                    "bypass_csp": True
                })

            context = await browser.new_context(**context_options)

            # Create new page
            page = await context.new_page()

            # Navigate to CRM login page
            login_url = f"{url.rstrip('/')}/MDP/"
            logger.info(f"Navigating to CRM: {login_url}")

            try:
                await page.goto(login_url, timeout=timeout, wait_until='domcontentloaded')
            except Exception as e:
                raise CRMLoginError(f"Failed to navigate to CRM login page: {e}")

            # Wait for page to load
            await asyncio.sleep(2)

            # Check if already logged in (redirected to main.aspx)
            current_url = page.url
            if 'main.aspx' in current_url:
                logger.info("Already logged in (redirected to main.aspx)")
            else:
                # Fill in login form
                logger.info("Filling in login credentials...")

                # Try different possible username field selectors
                username_selectors = [
                    'input[name="username"]',
                    'input[type="text"]',
                    'input[id*="user"]',
                    'input[class*="user"]',
                    'input[placeholder*="user" i]',
                ]

                username_field = None
                for selector in username_selectors:
                    try:
                        username_field = await page.wait_for_selector(selector, timeout=2000)
                        if username_field:
                            logger.info(f"Found username field with selector: {selector}")
                            break
                    except:
                        continue

                if not username_field:
                    raise CRMLoginError("Could not find username input field")

                # Fill username
                await username_field.fill(username)
                logger.info(f"Username entered: {username}")

                # Try different possible password field selectors
                password_selectors = [
                    'input[name="password"]',
                    'input[type="password"]',
                    'input[id*="pass"]',
                    'input[class*="pass"]',
                ]

                password_field = None
                for selector in password_selectors:
                    try:
                        password_field = await page.wait_for_selector(selector, timeout=2000)
                        if password_field:
                            logger.info(f"Found password field with selector: {selector}")
                            break
                    except:
                        continue

                if not password_field:
                    raise CRMLoginError("Could not find password input field")

                # Fill password
                await password_field.fill(password)
                logger.info("Password entered")

                # Try different possible submit button selectors
                submit_selectors = [
                    'button[type="submit"]',
                    'input[type="submit"]',
                    'button[id*="login"]',
                    'button[class*="login"]',
                    'button:has-text("Log")',
                    'button:has-text("Sign")',
                ]

                submit_button = None
                for selector in submit_selectors:
                    try:
                        submit_button = await page.wait_for_selector(selector, timeout=2000)
                        if submit_button:
                            logger.info(f"Found submit button with selector: {selector}")
                            break
                    except:
                        continue

                if not submit_button:
                    # Try pressing Enter instead
                    logger.info("Submit button not found, pressing Enter...")
                    await password_field.press('Enter')
                else:
                    # Click submit button
                    logger.info("Clicking login button...")
                    await submit_button.click()

            # Wait for login to complete (redirect to main.aspx)
            logger.info("Waiting for login to complete...")

            try:
                # Wait for navigation to main.aspx or any page that indicates successful login
                await page.wait_for_url("**/main.aspx**", timeout=timeout)
                logger.info("Login successful (redirected to main.aspx)")
            except Exception:
                # Check if we're on a different page that might indicate success
                current_url = page.url
                logger.warning(f"Did not redirect to main.aspx. Current URL: {current_url}")

                # Check for common error indicators
                page_content = await page.content()
                if any(err in page_content.lower() for err in ['error', 'invalid', 'failed']):
                    raise CRMLoginError("Login failed - error page detected")

                # If not an obvious error, proceed anyway
                logger.info("Proceeding despite no redirect to main.aspx")

            # Wait a bit for cookies to be set
            await asyncio.sleep(2)

            # Extract cookies
            cookies = await context.cookies()
            logger.info(f"Retrieved {len(cookies)} cookies")

            # Extract required cookies
            req_client_id = None
            org_id = None

            for cookie in cookies:
                if cookie['name'] == 'ReqClientId':
                    req_client_id = cookie['value']
                    logger.info(f"Found ReqClientId cookie: {req_client_id[:8]}...")
                elif cookie['name'] == 'orgId':
                    org_id = cookie['value']
                    logger.info(f"Found orgId cookie: {org_id[:8]}...")

            if not req_client_id:
                raise CRMLoginError("Could not extract ReqClientId cookie from session")

            if not org_id:
                raise CRMLoginError("Could not extract orgId cookie from session")

            # Success
            logger.info("CRM login completed successfully")

            return {
                'ReqClientId': req_client_id,
                'orgId': org_id
            }

        except CRMLoginError:
            raise
        except Exception as e:
            raise CRMLoginError(f"Unexpected error during CRM login: {e}")
        finally:
            # Clean up
            if context:
                try:
                    await context.close()
                except:
                    pass
            if browser:
                try:
                    await browser.close()
                except:
                    pass


async def login_and_save_session(
    url: str,
    username: str,
    password: str,
    session_file: str = "crm_session.json",
    headless: bool = False,
    incognito: bool = False
) -> Dict[str, str]:
    """
    Login to CRM and save session cookies to a file.

    Args:
        url: The CRM base URL
        username: CRM username
        password: CRM password
        session_file: Path to save session cookies
        headless: Whether to run browser in headless mode
        incognito: Whether to use strict incognito mode

    Returns:
        dict: Dictionary containing session cookies
    """
    import json

    cookies = await login_to_crm(url, username, password, headless=headless, incognito=incognito)

    # Save to file
    session_data = {
        'url': url,
        'username': username,
        'cookies': cookies,
        'timestamp': asyncio.get_event_loop().time()
    }

    with open(session_file, 'w') as f:
        json.dump(session_data, f, indent=2)

    logger.info(f"Session saved to: {session_file}")

    return cookies


def load_session_from_file(session_file: str = "crm_session.json") -> Optional[Dict[str, str]]:
    """
    Load previously saved CRM session cookies from a file.

    Args:
        session_file: Path to the session file

    Returns:
        dict: Dictionary containing session cookies, or None if file not found
    """
    import json
    import os

    if not os.path.exists(session_file):
        return None

    try:
        with open(session_file, 'r') as f:
            session_data = json.load(f)

        return session_data.get('cookies')

    except Exception as e:
        logger.warning(f"Failed to load session file: {e}")
        return None


if __name__ == "__main__":
    # Test the Playwright login module
    import sys
    import asyncio
    import json

    logging.basicConfig(level=logging.INFO)

    if len(sys.argv) < 3:
        print("Usage: python playwright_login.py <username> <password> [url] [headless]")
        print("\nExample:")
        print('  python playwright_login.py "DOMAIN\\\\user.name" "password" "https://internalcrm.macausjm-glp.com" false')
        sys.exit(1)

    username = sys.argv[1]
    password = sys.argv[2]
    url = sys.argv[3] if len(sys.argv) > 3 else "https://internalcrm.macausjm-glp.com"
    headless = sys.argv[4].lower() == 'true' if len(sys.argv) > 4 else False

    async def test_login():
        try:
            print(f"\nLogging in to CRM...")
            print(f"  URL: {url}")
            print(f"  Username: {username}")
            print(f"  Headless: {headless}\n")

            cookies = await login_to_crm(url, username, password, headless=headless, incognito=incognito)

            print("\nLogin successful!")
            print(f"  ReqClientId: {cookies['ReqClientId']}")
            print(f"  orgId: {cookies['orgId']}")

            # Save session
            session_file = "crm_session.json"
            session_data = {
                'url': url,
                'username': username,
                'cookies': cookies
            }

            with open(session_file, 'w') as f:
                json.dump(session_data, f, indent=2)

            print(f"\nSession saved to: {session_file}")

        except CRMLoginError as e:
            print(f"\nLogin failed: {e}")
            sys.exit(1)
        except Exception as e:
            print(f"\nUnexpected error: {e}")
            sys.exit(1)

    asyncio.run(test_login())
