"""
HyundaiCard Scraper - Main implementation
This scraper logs into HyundaiCard and retrieves transaction data.
"""

import asyncio
import logging
from typing import Self

from .keyboards import NppfsKeyboard
from .playwright_mobile import PlaywrightSessionManager
from .types import CardTransaction

logger = logging.getLogger(__name__)


class HyundaiCardTransaction(CardTransaction):
    card_name: str


class HyundaiCardScraper:
    """Scraper for HyundaiCard transaction information."""

    def __init__(self, headless: bool = False, base_url: str | None = None) -> None:
        self.base_url = base_url
        self._session_manager = PlaywrightSessionManager(headless, base_url)
        self._password_keyboard = NppfsKeyboard("webPwd")
        self._pin_keyboard = NppfsKeyboard("cardPwd")
        self.browser = None
        self.context = None
        self.page = None

    async def __aenter__(self) -> Self:
        """Async context manager entry."""
        self.browser, self.context, self.page = await self._session_manager.__aenter__()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
        """Async context manager exit."""
        await self._session_manager.__aexit__(exc_type, exc_val, exc_tb)
        self.browser = None
        self.context = None
        self.page = None

    async def navigate_to_login(self) -> None:
        """Navigate to the HyundaiCard login page."""
        logger.debug("Navigating to HyundaiCard...")
        target_url = self.base_url or "https://www.hyundaicard.com/index.jsp?forceUA=PC"
        await self.page.goto(target_url, wait_until="networkidle", timeout=60000)
        logger.debug("Login page loaded successfully")

    async def open_id_login_form(self) -> None:
        """Open the ID/password login form."""
        logger.debug("Opening ID login form...")

        # Click "다른 로그인 방법"
        other_login = await self.page.query_selector("text=다른 로그인 방법")
        if not other_login:
            raise Exception("Could not find '다른 로그인 방법' link")

        await other_login.click()
        logger.debug("  ✓ Opened login method selector")

        # Wait a moment for the options to appear
        await asyncio.sleep(1)

        # Click "아이디" option
        logger.debug("  Selecting ID login option...")
        id_option = await self.page.query_selector("text=아이디")
        if not id_option:
            raise Exception("Could not find ID login option")

        await id_option.click()
        logger.debug("  ✓ ID login form opened")

        # Wait for form to be ready
        await asyncio.sleep(1)

    async def enter_user_id(self, user_id: str) -> None:
        """Enter user ID in the login form."""
        logger.debug("Entering user ID: %s", user_id)

        # Find the user ID input field
        user_id_input = await self.page.query_selector("input#webMbrId")
        if not user_id_input:
            user_id_input = await self.page.query_selector('input[type="text"]')

        if not user_id_input:
            raise Exception("Could not find user ID input field")

        # Clear and enter user ID
        await user_id_input.click()
        await user_id_input.fill("")
        await user_id_input.type(user_id, delay=100)

        # Trigger events
        await user_id_input.evaluate("""(element) => {
            element.dispatchEvent(new Event('input', { bubbles: true }));
            element.dispatchEvent(new Event('change', { bubbles: true }));
            element.dispatchEvent(new Event('blur', { bubbles: true }));
        }""")

        logger.debug("User ID entered successfully")

    async def enter_password_via_keyboard(self, password: str) -> None:
        """
        Enter password using the on-screen keyboard.

        Args:
            password: The password to enter (alphanumeric and special characters)
        """
        await self._password_keyboard.enter_password(self.page, password)

    async def click_login_button(self) -> None:
        """Click the final login button."""
        logger.debug("Looking for login button...")

        # Find the login button
        login_button = await self.page.query_selector('button:has-text("로그인")')

        if not login_button:
            # Try finding by other methods
            all_buttons = await self.page.query_selector_all("button, a")
            for btn in all_buttons:
                try:
                    text = await btn.text_content()
                    if text and "로그인" in text.strip():
                        is_visible = await btn.is_visible()
                        if is_visible:
                            login_button = btn
                            break
                except Exception:
                    continue

        if not login_button:
            raise Exception("Could not find login button")

        logger.debug("Clicking login button...")
        await login_button.click()
        logger.debug("Login button clicked")

    async def enter_pin(self, pin: str) -> bool:
        """
        Enter credit card PIN using the on-screen keyboard.

        Args:
            pin: The credit card PIN (4-6 digits)
        """
        try:
            await self._pin_keyboard.enter_pin(self.page, pin)

            # Look for the confirm button (it's a regular button, not part of the keyboard)
            logger.debug("Looking for '확인' button...")
            await asyncio.sleep(0.5)

            # Look for the specific confirm button
            confirm_button = await self.page.query_selector("button#btnCardAuth")
            if not confirm_button:
                confirm_button = await self.page.query_selector('button:has-text("확인")')
            if not confirm_button:
                all_buttons = await self.page.query_selector_all("button")
                for btn in all_buttons:
                    text = await btn.text_content()
                    if text and "확인" in text:
                        is_visible = await btn.is_visible()
                        if is_visible:
                            confirm_button = btn
                            break

            if confirm_button:
                is_visible = await confirm_button.is_visible()
                if is_visible:
                    logger.debug("Clicking PIN confirm button...")
                    await confirm_button.click()
                    await asyncio.sleep(2)
                    logger.debug("PIN confirmed")
                else:
                    logger.warning("PIN confirm button found but not visible")
            else:
                logger.warning("PIN confirm button not found")

            return True
        except Exception:
            logger.debug("Could not enter PIN, it may not be required")
            return False

    async def login(self, user_id: str, password: str, pin: str | None = None) -> bool:
        """
        Perform login to HyundaiCard.

        Args:
            user_id: The user's ID
            password: The user's password
            pin: Optional credit card PIN for additional verification
        """
        await self.navigate_to_login()
        await self.open_id_login_form()
        await self.enter_user_id(user_id)
        await self.enter_password_via_keyboard(password)
        await self.click_login_button()

        # Wait for login to complete
        await asyncio.sleep(3)

        # Check if login was successful
        current_url = self.page.url
        logger.debug("Current URL after login: %s", current_url)

        # Check if PIN is required
        if pin:
            await self.enter_pin(pin)
            await asyncio.sleep(2)

        logger.debug("Login process completed")
        return True

    async def get_transactions(self) -> list[HyundaiCardTransaction]:
        """
        Extract recent transaction information from the card usage history page.

        Returns:
            List of transaction dictionaries
        """
        logger.debug("Navigating to transaction history...")

        # Create a new browser context with desktop user agent
        # The mobile context can't have its UA changed, so we need a new context
        desktop_ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"

        # Create desktop context with the logged-in session cookies
        desktop_context = await self.browser.new_context(
            user_agent=desktop_ua,
            viewport={"width": 1920, "height": 1080},
            storage_state=await self.context.storage_state(),  # Copy cookies and storage
        )

        # Create new page in desktop context
        desktop_page = await desktop_context.new_page()
        logger.debug("Created new desktop context with Chrome UA")

        # Navigate to transaction history page with desktop UA
        # Allow override via environment variable for testing
        import os

        transactions_url = os.getenv(
            "HYUNDAI_CARD_TRANSACTIONS_URL", "https://www.hyundaicard.com/cpa/cb/CPACB0101_01.hc"
        )
        await desktop_page.goto(transactions_url, wait_until="networkidle", timeout=60000)
        logger.debug("Navigated to %s", transactions_url)

        logger.debug("Extracting transaction data...")

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

        # Extract transactions from the page
        transactions = []

        # Find all transaction elements
        transaction_elements = await desktop_page.query_selector_all("#viewListArea .cel_list")

        for elem in transaction_elements:
            try:
                # Extract merchant name
                merchant_elem = await elem.query_selector(".p1_m_lt_1ln")
                merchant = await merchant_elem.text_content() if merchant_elem else ""

                # Extract amount
                amount_elem = await elem.query_selector(".price em")
                amount = await amount_elem.text_content() if amount_elem else ""

                # Extract divider items (card name, date, time, installment)
                divider_items = await elem.query_selector_all(".divr_dot .divr_txt")
                divider_texts = []
                for item in divider_items:
                    text = await item.text_content()
                    divider_texts.append(text.strip())

                # Parse divider texts
                card_name = divider_texts[0] if len(divider_texts) > 0 else ""
                date = divider_texts[1] if len(divider_texts) > 1 else ""
                time = divider_texts[2] if len(divider_texts) > 2 else ""
                installment = divider_texts[3] if len(divider_texts) > 3 else ""

                transaction = {
                    "merchant": merchant.strip(),
                    "amount": amount.strip(),
                    "card_name": card_name,
                    "transacted_at": f"{date} {time}".strip(),  #'transacted_at': '25. 11. 6 19:10'
                    "installment": installment,
                    "status": "",
                }

                transactions.append(transaction)

            except Exception as e:
                logger.warning("Failed to extract transaction: %s", e)
                continue

        # Clean up desktop context
        await desktop_context.close()

        logger.debug("✓ Extracted %d transactions", len(transactions))

        return transactions
