import ctypes
import os
import sys

# DPI修正 (最優先)
try:
    ctypes.windll.shcore.SetProcessDpiAwareness(1)
except:
    try:
        ctypes.windll.user32.SetProcessDPIAware()
    except:
        pass

import pyautogui
import time
import threading
import tkinter as tk
from tkinter import ttk, messagebox
from PIL import Image, ImageGrab
import keyboard

# ---------------------------------------------------------
# バージョン
# ---------------------------------------------------------
__version__ = "1.1"  # v1.1: マルチディスプレイ対応 (ImageGrab(all_screens=True))

# ---------------------------------------------------------
# 管理者権限
# ---------------------------------------------------------
if not ctypes.windll.shell32.IsUserAnAdmin():
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable,
                                       f'"{os.path.abspath(__file__)}"' if not getattr(sys, 'frozen', False) else None, None, 1)
    sys.exit()

# ---------------------------------------------------------
# 設定と画像読み込み（日本語パス対策）
# ---------------------------------------------------------
def 基点パス取得():
    # exe化された場合は exe と同じフォルダ、 .py 直接実行なら .py と同じフォルダ
    if getattr(sys, 'frozen', False):
        return os.path.dirname(sys.executable)
    return os.path.dirname(os.path.abspath(__file__))

稼働中 = False

# OpenCVの存在確認
try:
    import cv2
    cv2_available = True
except:
    cv2_available = False

def 画像データとして読み込む(フルパス):
    """OpenCVの日本語パス問題を避けるため、PIL経由で画像を開いてから渡す"""
    try:
        with Image.open(フルパス) as img:
            return img.convert('RGB')
    except:
        return None

# 仮想画面の左上座標 (マルチディスプレイ環境で 主モニタ以外が左/上にあると負値になる)
# Windows API: SM_XVIRTUALSCREEN=76, SM_YVIRTUALSCREEN=77
def 仮想画面の原点():
    user32 = ctypes.windll.user32
    return user32.GetSystemMetrics(76), user32.GetSystemMetrics(77)

# ---------------------------------------------------------
# メイン巡回ロジック
# ---------------------------------------------------------
def クリック実行ループ():
    global 稼働中
    while True:
        if 稼働中:
            パス = 基点パス取得()
            画像ファイル名リスト = [f for f in os.listdir(パス) if f.lower().endswith('.png')]

            if not 画像ファイル名リスト:
                time.sleep(2)
                continue

            found = False
            ログ追記(f"スキャン中... ({len(画像ファイル名リスト)}枚の画像)")

            for 名前 in 画像ファイル名リスト:
                if not 稼働中: break

                フルパス = os.path.join(パス, 名前)
                画像データ = 画像データとして読み込む(フルパス)

                if 画像データ is None: continue

                try:
                    # マルチディスプレイ対応: pyautogui.locateCenterOnScreen は主モニタしか撮らないため、
                    # ImageGrab.grab(all_screens=True) で仮想画面全体をキャプチャしてから locate する
                    # confidence=0.9: ac.py と同水準。色味・形がほぼ完全一致しないとクリックしない (誤爆防止)
                    全画面 = ImageGrab.grab(all_screens=True)
                    領域 = pyautogui.locate(画像データ, 全画面, confidence=0.9)

                    if 領域:
                        # 領域は仮想画面画像内のピクセル座標。実画面座標へは仮想画面の原点を足す
                        vx, vy = 仮想画面の原点()
                        cx = int(領域.left + 領域.width // 2 + vx)
                        cy = int(領域.top + 領域.height // 2 + vy)
                        ログ追記(f"★検知成功: {名前} -> ({cx},{cy})")
                        pyautogui.moveTo(cx, cy, duration=0.1)
                        pyautogui.mouseDown()
                        time.sleep(0.1)
                        pyautogui.mouseUp()
                        ログ追記("クリック完了。4秒待機に入ります")
                        found = True
                        time.sleep(4)
                        break
                except Exception as e:
                    if not cv2_available:
                        ログ追記("致命的エラー: OpenCVが認識されていません")
                        break

            if not found:
                time.sleep(1.5)
        else:
            time.sleep(1)

# ---------------------------------------------------------
# 制御
# ---------------------------------------------------------
def 状態切替():
    """Homeキー or ボタン押下でON/OFFトグル"""
    global 稼働中
    稼働中 = not 稼働中
    if 稼働中:
        切替ボタン.config(text="● 稼働中 (Homeで停止)", bg="#4CAF50")
        ログ追記("--- 監視開始 ---")
        リスト更新()
    else:
        切替ボタン.config(text="停止中 (Homeで開始)", bg="#F44336")
        ログ追記("--- 監視停止 ---")

def ログ追記(メッセージ):
    時刻 = time.strftime('%H:%M:%S')
    ログ表示欄.insert(0, f"[{時刻}] {メッセージ}")
    if ログ表示欄.size() > 50: ログ表示欄.delete(50, tk.END)

def リスト更新():
    画像リスト表示欄.delete(0, tk.END)
    パス = 基点パス取得()
    for f in [f for f in os.listdir(パス) if f.lower().endswith('.png')]:
        画像リスト表示欄.insert(tk.END, f)

def アプリ終了():
    os._exit(0)

# ---------------------------------------------------------
# UI
# ---------------------------------------------------------
ルート = tk.Tk()
ルート.title(f"AC Pro v{__version__} (マルチディスプレイ対応)")
ルート.geometry("400x520")
ルート.attributes("-topmost", True)
# 常駐機能を撤去したため、ウィンドウを閉じる=プロセス終了
ルート.protocol("WM_DELETE_WINDOW", アプリ終了)

枠 = ttk.Frame(ルート, padding="15")
枠.pack(fill=tk.BOTH, expand=True)

ヘッダー = ttk.Frame(枠)
ヘッダー.pack(fill=tk.X)
ttk.Label(ヘッダー, text="【検出対象ファイル】", font=("", 9, "bold")).pack(side=tk.LEFT)
tk.Button(ヘッダー, text="ⓘ",
          command=lambda: messagebox.showinfo("HELP",
              f"AC Pro v{__version__}\n\n"
              "同フォルダのPNGを探してクリックします。\n"
              "日本語フォルダ名 + マルチディスプレイ対応。\n"
              "Homeキーで監視のON/OFF切替。"),
          bd=0, font=("", 11)).pack(side=tk.RIGHT)

画像リスト表示欄 = tk.Listbox(枠, height=5, font=("Consolas", 9))
画像リスト表示欄.pack(fill=tk.X, pady=5)

切替ボタン = tk.Button(枠, text="停止中 (Homeで開始)", bg="#F44336", fg="white",
                      font=("", 11, "bold"), height=2, command=状態切替)
切替ボタン.pack(fill=tk.X, pady=10)

ttk.Label(枠, text="【詳細ログ】", font=("", 9, "bold")).pack(anchor=tk.W)
ログ表示欄 = tk.Listbox(枠, height=12, font=("Consolas", 9))
ログ表示欄.pack(fill=tk.BOTH, expand=True, pady=5)

リスト更新()
ログ追記(f"エンジン: {'OpenCV(有効)' if cv2_available else '標準(低精度)'}")

# ホットキー: Home (物理キーのため横取りされにくく、長時間稼働でも安定)
keyboard.add_hotkey('home', 状態切替)
threading.Thread(target=クリック実行ループ, daemon=True).start()

ルート.mainloop()
