"""MTK keyboard strategy for Shinhan Bank scraper."""

import asyncio
import logging

from playwright.async_api import Page

from ..errors import KeyboardError
from .base import KeyboardStrategy

logger = logging.getLogger(__name__)


class MtkKeyboard(KeyboardStrategy):
    """
    Keyboard strategy for Shinhan Bank's MTK (Mobile TransKey) keyboard.

    This keyboard has unique characteristics:
    - Uses #mtk_{field_name} selectors
    - Requires rearrange button tap to synchronize aria-labels
    - Mode switching between normal and special characters
    """

    # MTK-specific character mapping (overrides base class)
    SPECIAL_CHAR_KOREAN = {
        "~": "물결표시",
        "!": "느낌표",
        "@": "골뱅이",
        "#": "우물정",
        "$": "달러기호",
        "%": "퍼센트",
        "^": "꺽쇠",
        "&": "엠퍼샌드",
        "*": "별표",
        "(": "왼쪽괄호",
        ")": "오른쪽괄호",
        "-": "빼기",
        "_": "밑줄",
        "=": "등호",
        "+": "더하기",
        "[": "왼쪽대괄호",
        "]": "오른쪽대괄호",
        "{": "왼쪽중괄호",
        "}": "오른쪽중괄호",
        "\\": "역슬래시",
        "|": "세로선",
        ";": "세미콜론",
        ":": "콜론",
        "'": "작은따옴표",
        '"': "큰따옴표",
        ",": "쉼표",
        ".": "마침표",
        "<": "작음",
        ">": "큼",
        "/": "슬래시",
        "?": "물음표",
        "`": "어금기호",
    }

    def __init__(self, keyboard_id: str = "비밀번호"):
        """
        Initialize MTK keyboard.

        Args:
            keyboard_id: The ID suffix for the keyboard (e.g., "비밀번호", "계좌비밀번호")
        """
        self.keyboard_id = keyboard_id
        self.keyboard_selector = f"#mtk_{keyboard_id}"

    async def enter_password(self, page: Page, password: str) -> None:
        """Enter password using MTK keyboard."""
        logger.debug("Clicking password field to open MTK keyboard...")

        # Find and click password field
        password_field = await page.query_selector('input[type="password"]')
        if not password_field:
            raise KeyboardError("Could not find password field")

        await password_field.click()

        # Wait for keyboard to appear
        keyboard_div = await page.wait_for_selector(self.keyboard_selector, timeout=10000, state="attached")
        if not keyboard_div:
            raise KeyboardError("MTK keyboard did not appear")

        logger.debug("MTK keyboard appeared")
        await asyncio.sleep(0.5)

        # Synchronize keyboard by tapping rearrange button
        await self._synchronize_keyboard(page)

        # Enter password characters
        await self._enter_text(page, password)

        # Close keyboard
        await self._close_keyboard(page)

    async def enter_pin(self, page: Page, pin: str) -> None:
        """Enter numeric PIN using MTK keyboard."""
        logger.debug("Entering PIN via MTK keyboard...")

        # Find and click TransKey button twice
        keypad_button = await page.query_selector(f"#{self.keyboard_id}_tk_btn")
        if not keypad_button:
            raise KeyboardError("Could not find TransKey button")

        # First click: activate, second click: open keypad
        await keypad_button.click()
        await keypad_button.click()

        # Wait for keypad
        keypad_container = await page.wait_for_selector(self.keyboard_selector, state="visible", timeout=10000)
        if not keypad_container:
            raise KeyboardError("Could not find keypad container")

        # Enter each digit
        for digit in pin:
            digit_button = await keypad_container.query_selector(f'[aria-label="{digit}"]')
            if not digit_button:
                raise KeyboardError(f"Could not find button for digit: {digit}")
            await digit_button.tap()

        logger.debug("PIN entered successfully")

    async def _synchronize_keyboard(self, page: Page) -> None:
        """Tap rearrange button to synchronize aria-labels."""
        logger.debug("Synchronizing keyboard...")

        keyboard_div = await page.query_selector(self.keyboard_selector)
        rearrange_button = await keyboard_div.query_selector('a[aria-label="재배열"]')

        if not rearrange_button:
            logger.warning("Rearrange button not found")
            return

        # Capture initial aria-labels
        initial_buttons = await keyboard_div.query_selector_all('a[role="button"]')
        initial_labels = []
        for btn in initial_buttons[:10]:
            try:
                label = await btn.get_attribute("aria-label")
                initial_labels.append(label)
            except Exception:
                pass

        logger.debug("Before rearrange: %s", initial_labels)

        # Tap rearrange button
        await rearrange_button.tap()

        # Wait for aria-labels to change
        max_wait = 2.0
        poll_interval = 0.05
        elapsed = 0.0
        rearranged = False

        while elapsed < max_wait:
            await asyncio.sleep(poll_interval)
            elapsed += poll_interval

            keyboard_div = await page.query_selector(self.keyboard_selector)
            current_buttons = await keyboard_div.query_selector_all('a[role="button"]')
            current_labels = []
            for btn in current_buttons[:10]:
                try:
                    label = await btn.get_attribute("aria-label")
                    current_labels.append(label)
                except Exception:
                    pass

            if len(current_labels) == len(initial_labels) and len(current_labels) > 0:
                changes = sum(1 for i in range(len(initial_labels)) if initial_labels[i] != current_labels[i])
                if changes > 0:
                    logger.debug("After rearrange: %s", current_labels)
                    logger.debug("Keyboard synchronized (%d buttons rearranged after %.2fs)", changes, elapsed)
                    rearranged = True
                    break

        if not rearranged:
            logger.warning("Keyboard may not have rearranged after %.2fs", elapsed)

    async def _enter_text(self, page: Page, text: str) -> None:
        """Enter text using the MTK keyboard."""
        current_mode = "normal"
        special_chars = set(self.SPECIAL_CHAR_KOREAN.keys())

        for i, char in enumerate(text):
            logger.debug("Entering character %d/%d: %s", i + 1, len(text), char)

            # Switch keyboard mode if needed
            keyboard_div = await page.query_selector(self.keyboard_selector)

            if char in special_chars and current_mode == "normal":
                logger.debug("  Switching to special characters mode...")
                special_button = await keyboard_div.query_selector("#mtk_sp")
                if special_button:
                    await special_button.tap()
                    keyboard_div = await page.query_selector(self.keyboard_selector)
                    test_button = await keyboard_div.query_selector('a[aria-label="느낌표"]')
                    if test_button:
                        logger.debug("  ✓ Switched to special characters mode")
                        current_mode = "special"
                    else:
                        logger.warning("  특수키 button tapped but keyboard did not switch")
                else:
                    logger.warning("  Could not find 특수키 button via #mtk_sp")

            elif char not in special_chars and current_mode == "special":
                logger.debug("  Switching back to normal mode...")
                keyboard_div = await page.query_selector(self.keyboard_selector)
                normal_button = await keyboard_div.query_selector("#mtk_sp")
                if normal_button:
                    await normal_button.tap()
                    current_mode = "normal"
                    logger.debug("  ✓ Switched back to normal mode")

            # Find and click button using class-level mapping
            char_label = self.SPECIAL_CHAR_KOREAN.get(char, char)
            button_selector = f'a[aria-label="{char_label}"]'

            keyboard_div = await page.query_selector(self.keyboard_selector)
            button = await keyboard_div.query_selector(button_selector)

            if not button:
                # Fallback: manual search
                logger.debug("  Direct selector failed, searching manually...")
                all_buttons = await keyboard_div.query_selector_all('a[role="button"]')
                for btn in all_buttons:
                    try:
                        btn_aria = await btn.get_attribute("aria-label")
                        if btn_aria == char or btn_aria == char_label:
                            button = btn
                            logger.debug("  Found via manual search: aria='%s'", btn_aria)
                            break
                    except Exception:
                        continue

            if not button:
                raise KeyboardError(f"Could not find button for character: {char}")

            logger.debug("  Clicking button...")
            await button.tap()

        logger.debug("Text entered successfully")

    async def _close_keyboard(self, page: Page) -> None:
        """Close the MTK keyboard."""
        keyboard_div = await page.query_selector(self.keyboard_selector)
        submit_button = await keyboard_div.query_selector('a[aria-label="입력완료"]')

        if submit_button:
            logger.debug("Clicking submit button...")
            await submit_button.tap()
            logger.debug("Keyboard closed")
        else:
            logger.warning("Submit button not found, trying to close keyboard...")
            await page.keyboard.press("Enter")
