# -*- coding: utf-8 -*-
"""
微信群接龙秒接工具 v4.1 (指定内容版)
- 在v4.0基础上增加：自动OCR识别接龙消息中的"指定内容"
- 自动填写"微信号-指定内容"格式参与接龙
- 使用pytesseract进行屏幕文字识别
"""

import os
import sys
import time
import subprocess
import datetime
import re

script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))

CHECK_INTERVAL = 5
COOLDOWN_TIME = 60
MONITOR_MODE = True

MY_WECHAT_ID = "你的微信号"

LOG_FILE = os.path.join(script_dir, "jielong.log")


def install_deps():
    print("首次运行安装依赖，请稍候...")
    pkgs = ["opencv-python", "pyautogui", "pillow", "numpy", "pywin32", "pytesseract"]
    for pkg in pkgs:
        try:
            subprocess.run(
                [sys.executable, "-m", "pip", "install", pkg, "--user", "-q"],
                capture_output=True
            )
        except:
            pass
    
    tesseract_paths = [
        r"C:\Program Files\Tesseract-OCR\tesseract.exe",
        r"C:\Program Files (x86)\Tesseract-OCR\tesseract.exe",
    ]
    found = any(os.path.exists(p) for p in tesseract_paths)
    
    if not found:
        print("\n需要安装 Tesseract-OCR（文字识别引擎）")
        print("正在自动下载安装...")
        tesseract_url = "https://github.com/UB-Mannheim/tesseract/releases/download/v5.4.0.20240506/tesseract-ocr-w64-setup-5.4.0.20240506.exe"
        tesseract_installer = os.path.join(script_dir, "tesseract_setup.exe")
        try:
            subprocess.run(
                [sys.executable, "-m", "pip", "install", "requests", "--user", "-q"],
                capture_output=True
            )
            import requests
            r = requests.get(tesseract_url, stream=True, timeout=120)
            with open(tesseract_installer, "wb") as f:
                for chunk in r.iter_content(8192):
                    f.write(chunk)
            print("下载完成，正在安装（请点Next直到完成）...")
            subprocess.run([tesseract_installer, "/S"], timeout=300)
            os.remove(tesseract_installer)
        except Exception as e:
            print(f"自动安装失败：{e}")
            print("请手动下载安装：https://github.com/UB-Mannheim/tesseract/wiki")
    
    print("依赖安装完成，请重新运行！")
    input("按回车退出")
    sys.exit(1)

try:
    import cv2
    import numpy as np
    import pyautogui
    import win32gui
    import win32con
    import win32clipboard
    import pytesseract
except ImportError:
    install_deps()

tesseract_exe = None
for p in [r"C:\Program Files\Tesseract-OCR\tesseract.exe",
          r"C:\Program Files (x86)\Tesseract-OCR\tesseract.exe"]:
    if os.path.exists(p):
        tesseract_exe = p
        break

if tesseract_exe:
    pytesseract.pytesseract.tesseract_cmd = tesseract_exe

pyautogui.FAILSAFE = True
pyautogui.PAUSE = 0.2

FOLDER_SEARCH = os.path.join(script_dir, "0-把【微信顶部搜索框】截图拖进这个文件夹")
FOLDER_JOIN = os.path.join(script_dir, "1-把【聊天里的参与接龙按钮】截图拖进这个文件夹")
FOLDER_PLUS = os.path.join(script_dir, "2-把【接龙弹窗里的+号】截图拖进这个文件夹")
FOLDER_CONFIRM = os.path.join(script_dir, "3-把【弹窗底部提交按钮】截图拖进这个文件夹")
GROUP_NAME = "家1"


def log(msg):
    now = datetime.datetime.now().strftime("%H:%M:%S")
    line = f"[{now}] {msg}"
    print(line)
    try:
        with open(LOG_FILE, "a", encoding="utf-8") as f:
            f.write(line + "\n")
    except:
        pass


def set_clipboard(text):
    try:
        win32clipboard.OpenClipboard()
        win32clipboard.EmptyClipboard()
        win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, text)
        win32clipboard.CloseClipboard()
    except Exception:
        try:
            win32clipboard.CloseClipboard()
        except Exception:
            pass
        import subprocess as sp
        sp.run(['clip'], input=text.encode('utf-16le'), check=True)


def get_template_from_folder(folder_path):
    if not os.path.exists(folder_path):
        return None
    exts = ('.png', '.jpg', '.jpeg', '.bmp')
    for f in os.listdir(folder_path):
        if f.lower().endswith(exts):
            img_path = os.path.join(folder_path, f)
            if os.path.getsize(img_path) > 1024:
                return img_path
    return None


def find_button(template_path, threshold=0.75, prefer_bottom=False):
    if not template_path or not os.path.exists(template_path):
        return None
    
    template = cv2.imdecode(np.fromfile(template_path, dtype=np.uint8), cv2.IMREAD_GRAYSCALE)
    if template is None:
        return None
    
    screenshot = pyautogui.screenshot()
    screen = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2GRAY)
    
    all_matches = []
    for scale in [0.85, 0.9, 0.95, 1.0, 1.05, 1.1, 1.15]:
        tpl = cv2.resize(template, None, fx=scale, fy=scale)
        th, tw = tpl.shape
        if th > screen.shape[0] or tw > screen.shape[1]:
            continue
        res = cv2.matchTemplate(screen, tpl, cv2.TM_CCOEFF_NORMED)
        loc = np.where(res >= threshold)
        for pt in zip(*loc[::-1]):
            conf = res[pt[1], pt[0]]
            cx = pt[0] + tw // 2
            cy = pt[1] + th // 2
            all_matches.append((cx, cy, float(conf)))
    
    if not all_matches:
        return None
    
    deduped = []
    used = [False] * len(all_matches)
    for i in range(len(all_matches)):
        if used[i]:
            continue
        group = [all_matches[i]]
        for j in range(i + 1, len(all_matches)):
            if used[j]:
                continue
            dx = abs(all_matches[i][0] - all_matches[j][0])
            dy = abs(all_matches[i][1] - all_matches[j][1])
            if dx < 20 and dy < 20:
                group.append(all_matches[j])
                used[j] = True
        used[i] = True
        best_in_group = max(group, key=lambda m: m[2])
        deduped.append(best_in_group)
    
    if prefer_bottom and len(deduped) > 1:
        result = max(deduped, key=lambda m: m[1])
    else:
        result = max(deduped, key=lambda m: m[2])
    
    return result


def click_found(folder, desc, timeout=8, prefer_bottom=False):
    tpl = get_template_from_folder(folder)
    if not tpl:
        log(f"  [!] 文件夹里没找到截图：{os.path.basename(folder)}")
        return None
    
    start = time.time()
    while time.time() - start < timeout:
        btn = find_button(tpl, prefer_bottom=prefer_bottom)
        if btn:
            x, y, conf = btn
            screen_w, screen_h = pyautogui.size()
            if x > screen_w - 80 and y < 80:
                time.sleep(0.1)
                continue
            log(f"  [OK] 找到{desc}，置信度{conf:.2f}，位置({x},{y})")
            pyautogui.click(x, y)
            return (x, y)
        time.sleep(0.3)
    log(f"  [X] 超时没找到{desc}")
    return None


def ocr_screen_for_content():
    log("[OCR] 正在识别接龙消息中的指定内容...")
    try:
        screenshot = pyautogui.screenshot()
        img = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
        
        h, w = img.shape[:2]
        crop = img[int(h*0.15):int(h*0.55), int(w*0.2):int(w*0.8)]
        
        gray = cv2.cvtColor(crop, cv2.COLOR_BGR2GRAY)
        _, thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY)
        
        text = pytesseract.image_to_string(thresh, lang='chi_sim+eng', config='--psm 6')
        log(f"[OCR] 识别到文字：{text.strip()[:100]}")
        
        patterns = [
            r'指定字母[为：:]\s*(\S+)',
            r'指定内容[为：:]\s*(\S+)',
            r'指定[为：:]\s*(\S+)',
            r'字母[为：:]\s*([a-zA-Z]+)',
            r'代号[为：:]\s*(\S+)',
            r'口令[为：:]\s*(\S+)',
        ]
        
        for pattern in patterns:
            match = re.search(pattern, text)
            if match:
                content = match.group(1).strip()
                log(f"[OCR] 识别到指定内容：{content}")
                return content
        
        log("[OCR] 未识别到指定内容，将只填写微信号")
        return ""
        
    except Exception as e:
        log(f"[OCR] 识别失败：{e}")
        return ""


def activate_wechat():
    log("[1/7] 查找微信窗口...")
    hwnd = None
    for cls in ["WeChatMainWndForPC", "WeChatMainWnd"]:
        hwnd = win32gui.FindWindow(cls, None)
        if hwnd:
            break
    if not hwnd:
        hwnd = win32gui.FindWindow(None, "微信")
    if not hwnd:
        log("[X] 没找到微信，请先打开电脑版微信")
        return False
    
    if win32gui.IsIconic(hwnd):
        win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
        time.sleep(1.5)
    
    log("[OK] 微信已就绪")
    return True


def search_group():
    log(f"[2/7] 搜索进入「{GROUP_NAME}」群...")
    
    pyautogui.press('escape')
    time.sleep(0.5)
    
    result = click_found(FOLDER_SEARCH, "微信搜索框", timeout=5)
    if not result:
        log("  [!] 没找到搜索框，请确保0号文件夹里有搜索框截图")
        return False
    
    time.sleep(1.0)
    
    pyautogui.hotkey('ctrl', 'a')
    time.sleep(0.2)
    pyautogui.press('backspace')
    time.sleep(0.3)
    
    set_clipboard(GROUP_NAME)
    time.sleep(0.2)
    pyautogui.hotkey('ctrl', 'v')
    time.sleep(2.0)
    
    pyautogui.press('enter')
    time.sleep(1.5)
    
    pyautogui.press('escape')
    time.sleep(0.5)
    
    log(f"[OK] 已搜索「{GROUP_NAME}」")
    return True


def check_images():
    missing = []
    if not get_template_from_folder(FOLDER_SEARCH):
        missing.append("0号文件夹：微信顶部搜索框")
    if not get_template_from_folder(FOLDER_JOIN):
        missing.append("1号文件夹：聊天里的参与接龙按钮")
    if not get_template_from_folder(FOLDER_PLUS):
        missing.append("2号文件夹：弹窗里的+号")
    if not get_template_from_folder(FOLDER_CONFIRM):
        missing.append("3号文件夹：底部提交按钮")
    
    if missing:
        print("="*50)
        print("  [!] 请把截图拖进对应文件夹：")
        for m in missing:
            print(f"   - {m}")
        print("\n  方法：截好图直接拖进对应名字的文件夹就行，不用改名！")
        print("="*50)
        input("\n拖好图后按回车继续...")
        return False
    return True


def do_jielong_with_content():
    log("[3/7] 查找接龙按钮...")
    if not click_found(FOLDER_JOIN, "聊天里的「参与接龙」按钮", timeout=15, prefer_bottom=True):
        return False
    time.sleep(1.8)
    
    specified = ocr_screen_for_content()
    
    if specified:
        entry_text = f"{MY_WECHAT_ID}-{specified}"
    else:
        entry_text = MY_WECHAT_ID
    log(f"[4/7] 将填写内容：{entry_text}")
    
    log("[5/7] 查找+号按钮...")
    if not click_found(FOLDER_PLUS, "弹窗里的「+」号", timeout=10):
        return False
    time.sleep(1.0)
    
    log("[6/7] 填写指定内容...")
    pyautogui.hotkey('ctrl', 'a')
    time.sleep(0.2)
    set_clipboard(entry_text)
    time.sleep(0.2)
    pyautogui.hotkey('ctrl', 'v')
    time.sleep(0.5)
    
    log("[7/7] 查找提交按钮...")
    ok = click_found(FOLDER_CONFIRM, "底部提交按钮", timeout=6)
    if not ok:
        ok = click_found(FOLDER_CONFIRM, "提交按钮", timeout=3)
        if not ok:
            return False
    time.sleep(0.5)
    
    log("接龙成功！")
    return True


def run_once():
    if not activate_wechat():
        input("按回车退出")
        return
    
    try:
        search_group()
    except Exception as e:
        log(f"搜群出错，你可以手动进群：{e}")
    
    if do_jielong_with_content():
        print("\n" + "="*50)
        print("  接龙成功！")
        print("="*50)
    else:
        print("\n" + "="*50)
        print("  本次未检测到接龙或操作失败")
        print("="*50)
    time.sleep(2)


def run_monitor():
    log("="*50)
    log("  持续监控模式已启动（指定内容版）")
    log(f"  监控群：{GROUP_NAME}")
    log(f"  微信号：{MY_WECHAT_ID}")
    log(f"  检测间隔：{CHECK_INTERVAL}秒")
    log(f"  接龙冷却：{COOLDOWN_TIME}秒")
    log(f"  按 Ctrl+C 停止监控")
    log("="*50)
    
    if not activate_wechat():
        input("按回车退出")
        return
    
    last_success_time = 0
    round_num = 0
    
    while True:
        try:
            round_num += 1
            now = time.time()
            
            if last_success_time > 0:
                elapsed = int(now - last_success_time)
                remaining = COOLDOWN_TIME - elapsed
                if remaining > 0:
                    log(f"  冷却中，还剩{remaining}秒...")
                    time.sleep(min(remaining, 5))
                    continue
            
            log(f"--- 第{round_num}轮检测 ---")
            
            try:
                search_group()
            except Exception as e:
                log(f"搜群出错：{e}")
            
            if do_jielong_with_content():
                last_success_time = time.time()
                log(f"接龙成功！冷却{COOLDOWN_TIME}秒后继续监控...")
            else:
                log(f"暂无接龙，{CHECK_INTERVAL}秒后重试...")
            
            time.sleep(CHECK_INTERVAL)
            
        except KeyboardInterrupt:
            log("\n监控已停止（按Ctrl+C）")
            break
        except Exception as e:
            log(f"出错：{e}")
            time.sleep(10)


def main():
    print("="*50)
    print("  微信群接龙秒接工具 v4.1 (指定内容版)")
    print(f"  自动进「{GROUP_NAME}」群 | 自动识别指定内容")
    print(f"  微信号：{MY_WECHAT_ID}")
    print("="*50)
    
    while not check_images():
        pass
    
    if MONITOR_MODE:
        run_monitor()
    else:
        run_once()


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n已退出")
    except Exception as e:
        print(f"\n出错：{e}")
        import traceback
        traceback.print_exc()
        input("\n按回车退出")