""" automation/defense_popup.py — 수비 팝업 조작 수비 버튼 클릭, 수비 시퀀스 입력, 실책 수비 팝업 처리. """ from __future__ import annotations from typing import Any from playwright.sync_api import Page from core.config_loader import defense_button_id_map, position_number_map from core.field_calculator import ( extract_defense_sequence, extract_error_position, infer_error_position_fallback, is_throwing_error, ) from automation.page_helpers import get_last_visible_locator def click_defense_button_robustly(page: Page, position: str, click_count: int = 1) -> bool: """수비 포지션 버튼을 안정적으로 클릭 ID 기반 → value 기반 → label 기반 순서로 시도 """ btn_map = defense_button_id_map() pos_num = position_number_map() # 1) ID 기반 button_selector = btn_map.get(position) if button_selector: loc = page.locator(button_selector) if loc.count() > 0: for _ in range(click_count): loc.click(force=True) page.wait_for_timeout(60) return True # 2) value 기반 value = pos_num.get(position) if value: loc = page.locator(f"input[name='defenseNumberBtn'][value='{value}']") if loc.count() > 0: for _ in range(click_count): loc.click(force=True) page.wait_for_timeout(60) return True # 3) label 기반 all_buttons = page.locator("input[name='defenseNumberBtn']").all() for btn in all_buttons: label = (btn.get_attribute("id") or "").lower() if position in label or label in position: for _ in range(click_count): btn.click(force=True) page.wait_for_timeout(60) return True return False def clear_defense_selections(page: Page) -> None: """수비 선택 초기화""" page.evaluate( """() => { document.querySelectorAll("input[name='defenseNumberBtn']").forEach(btn => { btn.checked = false; }); }""" ) def click_defense_sequence_in_popup( page: Page, sequence: list[str], complete_button_selector: str | None = None, ) -> None: """수비 시퀀스 순서대로 클릭 후 완료 버튼 클릭""" for position in sequence: click_defense_button_robustly(page, position) page.wait_for_timeout(80) if complete_button_selector: btn = get_last_visible_locator(page, complete_button_selector) if btn: btn.click() page.wait_for_timeout(120) def fill_runner_out_defense( page: Page, text: str, sequence_override: list[str] | None = None, ) -> None: """주루 아웃 수비 팝업 처리""" page.wait_for_timeout(300) sequence = sequence_override or extract_defense_sequence(text) if sequence: click_defense_sequence_in_popup(page, sequence) def fill_error_defense_popup(page: Page, text: str) -> None: """실책 수비 팝업 처리""" defense_sequence = extract_defense_sequence(text) if len(defense_sequence) >= 2: click_defense_sequence_in_popup(page, defense_sequence) else: error_position = extract_error_position(text) if not error_position: error_position = infer_error_position_fallback(text) click_count = 2 if is_throwing_error(text) else 1 click_defense_button_robustly(page, error_position, click_count) complete_button = get_last_visible_locator(page, "#btnNext") if complete_button is None: complete_button = get_last_visible_locator(page, "#btnAdd") if complete_button: complete_button.click() page.wait_for_timeout(120)