#!/usr/bin/env python3
"""
Type Text Primitive Operation

This module provides realistic text typing functionality for browser automation.
Simulates human-like typing with:
- Character grouping (typing bursts)
- Variable delays between characters and groups
- Occasional typos with corrections
- Natural rhythm variations
"""

import asyncio
import random
from typing import Dict, Any, List
from patchright.async_api  import Page


class TypeText:
    """
    Type Text with Human-like Typing Patterns

    Implements realistic typing behavior that mimics human typing patterns:
    - Groups characters into typing bursts (2-4 chars)
    - Short delays within groups (fast typing)
    - Longer delays between groups (thinking pauses)
    - Occasional typos with backspace corrections
    - Variable rhythm based on character type
    - Natural hesitations on punctuation/spaces

    Usage:
        typer = TypeText()
        result = await typer.type(page, text, base_delay=50)
    """

    def __init__(self):
        """Initialize the type text handler."""
        print("⌨️ TypeText initialized")

        # Characters that typically cause slowdowns
        self.slow_chars = {'.', ',', '!', '?', ':', ';', '\n', '@', '#', '$', '%'}

        # Common typo mappings (adjacent keys on QWERTY keyboard)
        self.typo_map = {
            'a': ['s', 'q', 'z'],
            'b': ['v', 'n', 'g'],
            'c': ['x', 'v', 'd'],
            'd': ['s', 'f', 'e'],
            'e': ['w', 'r', 'd'],
            'f': ['d', 'g', 'r'],
            'g': ['f', 'h', 't'],
            'h': ['g', 'j', 'y'],
            'i': ['u', 'o', 'k'],
            'j': ['h', 'k', 'u'],
            'k': ['j', 'l', 'i'],
            'l': ['k', 'o', 'p'],
            'm': ['n', 'j', 'k'],
            'n': ['b', 'm', 'h'],
            'o': ['i', 'p', 'l'],
            'p': ['o', 'l'],
            'q': ['w', 'a'],
            'r': ['e', 't', 'f'],
            's': ['a', 'd', 'w'],
            't': ['r', 'y', 'g'],
            'u': ['y', 'i', 'j'],
            'v': ['c', 'b', 'f'],
            'w': ['q', 'e', 's'],
            'x': ['z', 'c', 's'],
            'y': ['t', 'u', 'h'],
            'z': ['a', 'x'],
        }

    async def type(self, page: Page, text: str, base_delay: int = 40) -> Dict[str, Any]:
        """
        Type text with human-like patterns at the currently focused element.

        IMPORTANT: The target element should already be clicked/focused before calling this method.
        This method will clear any existing text in the focused element before typing.

        Args:
            page (Page): Playwright page to use
            text (str): Text to type
            base_delay (int): Base delay in milliseconds (default: 50)

        Returns:
            Dict containing typing result and text information
        """
        try:
            print(f"⌨️ Typing text: '{text[:50]}{'...' if len(text) > 50 else ''}'")

            # Check if focused element contains text and clear it
            try:
                # Get the value of the focused element
                focused_value = await page.evaluate("""
                    () => {
                        const el = document.activeElement;
                        return el && (el.value !== undefined ? el.value : el.textContent);
                    }
                """)

                if focused_value and focused_value.strip():
                    print(f"🗑️ Clearing existing text in focused element")
                    # Select all and delete
                    await page.keyboard.down('Control')
                    await asyncio.sleep(0.02)
                    await page.keyboard.press('KeyA')
                    await asyncio.sleep(0.01)
                    await page.keyboard.up('Control')
                    await asyncio.sleep(0.05)
                    
                    await page.keyboard.press('Backspace')
                    await asyncio.sleep(0.1)
            except Exception as e:
                print(f"⚠️ Could not check/clear focused element: {e}")

            # Split text into character groups
            groups = self._group_characters(text)

            chars_typed = 0
            typos_made = 0

            for group_idx, group in enumerate(groups):
                # Type each character in the group
                for char_idx, char in enumerate(group):
                    # Decide if we should make a typo (5% chance, not on last char of text)
                    should_typo = (
                        random.random() < 0.05 and
                        chars_typed < len(text) - 1 and
                        char.lower() in self.typo_map
                    )

                    if should_typo:
                        # Type wrong character
                        typo_char = random.choice(self.typo_map[char.lower()])
                        await page.keyboard.press(typo_char)
                        typos_made += 1

                        # Brief pause to "realize" the mistake
                        await asyncio.sleep(random.uniform(0.1, 0.3))

                        # Delete the typo
                        await page.keyboard.press('Backspace')
                        await asyncio.sleep(random.uniform(0.05, 0.15))

                    # Type the correct character
                    await page.keyboard.press(char)
                    chars_typed += 1

                    # Delay within group (fast typing)
                    delay = self._calculate_char_delay(char, base_delay, within_group=True)
                    await asyncio.sleep(delay / 1000)

                # Delay between groups (thinking pause) - but not after last group
                if group_idx < len(groups) - 1:
                    group_pause = self._calculate_group_pause(base_delay)
                    await asyncio.sleep(group_pause / 1000)

            result = {
                "success": True,
                "text_length": len(text),
                "chars_typed": chars_typed,
                "typos_made": typos_made,
                "url": page.url
            }

            print(f"✅ Text typed: {len(text)} characters (with {typos_made} typos corrected)")
            return result

        except Exception as e:
            error_result = {
                "success": False,
                "error": str(e)
            }
            print(f"❌ Text typing failed: {e}")
            return error_result

    def _group_characters(self, text: str) -> List[str]:
        """
        Split text into character groups (typing bursts).

        Groups of 2-4 characters simulate natural typing rhythm where
        people type in bursts with small pauses between.

        Args:
            text (str): Text to group

        Returns:
            List of character group strings
        """
        groups = []
        i = 0

        while i < len(text):
            # Random group size (2-4 characters)
            group_size = random.randint(2, 4)

            # Extract group (don't exceed text length)
            group = text[i:i + group_size]
            groups.append(group)

            i += group_size

        return groups

    def _calculate_char_delay(self, char: str, base_delay: int, within_group: bool = True) -> float:
        """
        Calculate delay after typing a character.

        Args:
            char (str): Character just typed
            base_delay (int): Base delay in milliseconds
            within_group (bool): Whether this is within a group (faster) or between groups

        Returns:
            Delay in milliseconds
        """
        if within_group:
            # Fast typing within a group
            delay = base_delay * random.uniform(0.2, 0.5)
        else:
            # Slower typing between groups
            delay = base_delay * random.uniform(0.9, 1.3)

        # Extra delay for punctuation and special characters
        if char in self.slow_chars:
            delay *= random.uniform(1.3, 2.1)

        # Slight delay for uppercase (shift key)
        elif char.isupper():
            delay *= random.uniform(1.1, 1.4)

        # Numbers sometimes take longer
        elif char.isdigit():
            delay *= random.uniform(1.0, 1.3)

        return delay

    def _calculate_group_pause(self, base_delay: int) -> float:
        """
        Calculate pause between character groups (thinking time).

        Args:
            base_delay (int): Base delay in milliseconds

        Returns:
            Pause duration in milliseconds
        """
        # Longer pauses between groups (thinking/hesitation)
        pause = base_delay * random.uniform(2.0, 4.0)

        # Occasionally longer pauses (15% chance) - simulating distraction
        if random.random() < 0.15:
            pause *= random.uniform(2.0, 3.5)

        return pause
