"""
微信自动登录（u2）— 检测未登录 → 账号密码登录

适配：微信 8.0.56+ / Redmi Note 13 (1080x2400)
"""

from __future__ import annotations

import logging
import re
from typing import Any, Dict, List

logger = logging.getLogger(__name__)

WX_PKG = "com.tencent.mm"

LOGIN_PAGE_MARKERS = [
    "登录", "注册", "用手机号登录", "用微信号", "QQ号", "邮箱",
    "Sign in", "Log in", "Log In",
]
MAIN_MARKERS = ["通讯录", "发现", "我", "微信"]

# 红米 Note 13 1080x2400 近似坐标（降级点击）
COORD_LOGIN_BTN = (540, 2050)
COORD_WECHAT_ID_LINK = (540, 1680)
COORD_FORM_LOGIN = (540, 2180)


class WeChatAutoLogin:
    """微信登录状态检测 + 密码登录"""

    def __init__(self, skill):
        self.s = skill

    def _xml(self) -> str:
        try:
            return self.s.d.dump_hierarchy() or ""
        except Exception as exc:
            logger.warning(f"[auto_login] dump_hierarchy 失败: {exc}")
            return ""

    def _activity(self) -> str:
        try:
            cur = self.s.d.app_current()
            return str(cur.get("activity") or "")
        except Exception:
            return ""

    def _ui_sample(self, xml: str = "", limit: int = 24) -> List[str]:
        src = xml or self._xml()
        texts = re.findall(r'text="([^"]{1,48})"', src)
        descs = re.findall(r'content-desc="([^"]{1,48})"', src)
        seen: set[str] = set()
        out: List[str] = []
        for t in texts + descs:
            t = t.strip()
            if not t or t in seen:
                continue
            seen.add(t)
            out.append(t)
            if len(out) >= limit:
                break
        return out

    def _tap(self, x: int, y: int) -> None:
        try:
            self.s.d.click(x, y)
        except Exception:
            self.s.click(x, y)

    def _cold_start_wechat(self) -> None:
        try:
            self.s.d.app_stop(WX_PKG)
            self.s.sleep(0.8)
        except Exception:
            pass
        self.s.launch()
        self.s.sleep(2.5)

    def _dismiss_dialogs(self) -> None:
        for label in (
            "允许", "同意", "同意并继续", "同意并登录", "我知道了",
            "确定", "继续", "Allow", "OK",
        ):
            if self.s.click_text(label, timeout=1) or self.s.click_contains(label, timeout=1):
                self.s.sleep(0.8)

    def check_login_state(self) -> Dict[str, Any]:
        """检测是否已登录微信主界面"""
        try:
            if not self.s.is_running():
                self.s.launch()
            else:
                self.s.d.app_start(WX_PKG)
            self.s.sleep(2.0)
            self._dismiss_dialogs()

            xml = self._xml()
            activity = self._activity()

            main_hits = sum(1 for m in ("通讯录", "发现", "我") if m in xml)
            if main_hits >= 2 or (
                "LauncherUI" in activity and "通讯录" in xml
            ):
                return {
                    "logged_in": True,
                    "state": "logged_in",
                    "activity": activity,
                }

            if any(m in xml for m in LOGIN_PAGE_MARKERS) or any(
                k in activity for k in ("Login", "Welcome", "MobileLogin", "LoginUI")
            ):
                return {
                    "logged_in": False,
                    "state": "login_page",
                    "activity": activity,
                    "ui_sample": self._ui_sample(xml),
                }

            if self.s.click_text("通讯录", timeout=2):
                return {
                    "logged_in": True,
                    "state": "logged_in",
                    "activity": activity,
                }

            return {
                "logged_in": False,
                "state": "unknown",
                "activity": activity,
                "ui_sample": self._ui_sample(xml),
            }
        except Exception as exc:
            logger.exception(f"[auto_login] check_login_state: {exc}")
            return {"logged_in": False, "state": "error", "error": str(exc)}

    def _goto_password_login(self) -> None:
        """从欢迎页/登录页进入账号密码输入界面"""
        self._cold_start_wechat()
        self._dismiss_dialogs()

        xml = self._xml()
        if xml.count("EditText") >= 2:
            return

        clicked = False
        for label in ("登录", "Log in", "Log In", "Sign in"):
            if self.s.click_text(label, timeout=2) or self.s.click_contains(label, timeout=2):
                clicked = True
                self.s.sleep(1.2)
                break
        if not clicked:
            self._tap(*COORD_LOGIN_BTN)
            self.s.sleep(1.2)

        self._dismiss_dialogs()

        for label in (
            "用微信号/QQ号/邮箱登录",
            "用微信号/QQ号/邮箱",
            "用微信号/QQ/邮箱登录",
            "用微信号",
            "QQ号/邮箱",
            "密码登录",
            "用密码登录",
            "更多登录方式",
            "其他登录方式",
        ):
            if self.s.click_contains(label, timeout=2):
                logger.info(f"[auto_login] 进入登录: {label}")
                self.s.sleep(1.2)
                break
        else:
            if "手机号" in self._xml() and "EditText" in self._xml():
                self._tap(*COORD_WECHAT_ID_LINK)
                self.s.sleep(1.2)

        for label in (
            "用微信号/QQ号/邮箱登录",
            "用微信号/QQ号/邮箱",
            "密码登录",
        ):
            if self.s.click_contains(label, timeout=1):
                self.s.sleep(1.0)
                break

    def _edit_count(self) -> int:
        try:
            edits = self.s.d(className="android.widget.EditText")
            return edits.count if hasattr(edits, "count") else len(list(edits))
        except Exception:
            return 0

    def _fill_edittexts(self, account: str, password: str) -> bool:
        """填写账号/密码（优先 EditText 顺序，降级 hint/坐标）"""
        d = self.s.d
        count = self._edit_count()

        if count >= 2:
            try:
                edits = d(className="android.widget.EditText")
                edits[0].click()
                self.s.sleep(0.3)
                edits[0].clear_text()
                edits[0].set_text(account)
                self.s.sleep(0.4)
                edits[1].click()
                self.s.sleep(0.3)
                edits[1].clear_text()
                edits[1].set_text(password)
                return True
            except Exception as exc:
                logger.warning(f"[auto_login] EditText[0,1] 失败: {exc}")

        if count == 1:
            try:
                edits = d(className="android.widget.EditText")
                edits[0].click()
                self.s.sleep(0.3)
                edits[0].clear_text()
                edits[0].set_text(account)
                self.s.sleep(0.5)
                if self.s.click_text("下一步", timeout=2) or self.s.click_contains("下一步", timeout=2):
                    self.s.sleep(1.5)
                pwd = d(className="android.widget.EditText")
                if pwd.count >= 1:
                    pwd[0].click()
                    pwd[0].clear_text()
                    pwd[0].set_text(password)
                    return True
            except Exception as exc:
                logger.warning(f"[auto_login] 分步登录失败: {exc}")

        filled_account = False
        for hint in ("微信号", "QQ号", "邮箱", "账号", "手机号", "WeChat ID"):
            if self.s.click_contains(hint, timeout=1):
                self.s.input_text(account, clear=True)
                filled_account = True
                self.s.sleep(0.5)
                break
        if not filled_account and count >= 1:
            try:
                d(className="android.widget.EditText")[0].set_text(account)
                filled_account = True
            except Exception:
                pass

        for hint in ("密码", "请输入密码", "Password"):
            if self.s.click_contains(hint, timeout=1):
                self.s.input_text(password, clear=True)
                return True

        if count >= 2:
            try:
                edits = d(className="android.widget.EditText")
                edits[1].set_text(password)
                return bool(account)
            except Exception:
                pass

        return False

    def _submit_login(self) -> bool:
        """提交登录（避免误点欢迎页「登录」）"""
        if self._edit_count() >= 1:
            for label in ("同意并登录", "登录", "Log In", "Sign in"):
                elems = self.s.d(textContains=label)
                try:
                    n = elems.count if hasattr(elems, "count") else len(list(elems))
                except Exception:
                    n = 0
                if n == 1 and self.s.click_contains(label, timeout=2):
                    return True
                if n > 1:
                    try:
                        elems[n - 1].click()
                        return True
                    except Exception:
                        pass
            self._tap(*COORD_FORM_LOGIN)
            return True
        return (
            self.s.click_text("登录", timeout=2)
            or self.s.click_contains("登录", timeout=2)
        )

    def login_by_password(self, account: str, password: str) -> Dict[str, Any]:
        """
        账号密码登录微信。
        account: 微信号 / 手机号 / 邮箱（如 Lytiao1）
        password: 登录密码
        """
        account = (account or "").strip()
        password = password or ""
        steps: List[str] = []

        if not account or not password:
            return {
                "success": False,
                "error": "缺少 account 或 password",
                "steps": steps,
            }

        state = self.check_login_state()
        steps.append(f"check:{state.get('state')}")
        if state.get("logged_in"):
            return {
                "success": True,
                "already_logged_in": True,
                "state": state,
                "account": account,
                "steps": steps,
            }

        try:
            self._goto_password_login()
            steps.append("goto_password_login")
            steps.append(f"edits:{self._edit_count()}")

            if not self._fill_edittexts(account, password):
                steps.append("fill_edittexts_partial")
            else:
                steps.append("fill_edittexts_ok")

            submitted = self._submit_login()
            steps.append(f"submit:{submitted}")
            self.s.sleep(4.0)
            self._dismiss_dialogs()
            self.s.sleep(2.0)

            final = self.check_login_state()
            steps.append(f"final:{final.get('state')}")

            if final.get("logged_in"):
                return {
                    "success": True,
                    "already_logged_in": False,
                    "state": final,
                    "account": account,
                    "steps": steps,
                }

            xml = self._xml()
            need_verify = any(
                k in xml
                for k in ("验证", "安全验证", "滑块", "验证码", "人脸识别", "新设备")
            )
            return {
                "success": False,
                "error": "登录未完成，可能需要安全验证" if need_verify else "未能进入微信主界面",
                "need_verify": need_verify,
                "state": final,
                "account": account,
                "steps": steps,
                "activity": final.get("activity", ""),
                "ui_sample": self._ui_sample(xml),
            }
        except Exception as exc:
            logger.exception(f"[auto_login] login_by_password: {exc}")
            return {
                "success": False,
                "error": str(exc),
                "account": account,
                "steps": steps,
                "ui_sample": self._ui_sample(),
            }

    def ensure_logged_in(self, account: str, password: str) -> Dict[str, Any]:
        """未登录则自动密码登录"""
        state = self.check_login_state()
        if state.get("logged_in"):
            return {"success": True, "action": "skip", "state": state}
        result = self.login_by_password(account, password)
        result["action"] = "login"
        return result
