import pyautogui
import cv2
import numpy as np
import time
import random
import threading
from PIL import ImageGrab
import keyboard
import win32gui
import win32con
import win32api
import json
import os
from datetime import datetime

class Metin2Bot:
    def __init__(self, config_file="bot_config.json"):
        self.running = False
        self.paused = False
        self.config = self.load_config(config_file)
        
        # Pencere ayarları
        self.window_title = "Metin2"
        self.window_handle = None
        self.window_region = None
        
        # Zaman sayaçları
        self.last_pickup_time = time.time()
        self.last_hp_check = time.time()
        self.last_skill_time = time.time()
        self.pickup_interval = random.uniform(5, 10)
        
        # Bot durumu
        self.current_target = None
        self.attack_mode = False
        self.stats = {
            "metin_destroyed": 0,
            "items_picked": 0,
            "start_time": None,
            "total_clicks": 0
        }
        
        # Görüntü şablonları
        self.templates = {}
        self.load_templates()
        
    def load_config(self, config_file):
        """Konfigürasyon dosyasını yükle"""
        default_config = {
            "window_width": 1600,
            "window_height": 900,
            "metin_colors": {
                "lower": [80, 80, 80],
                "upper": [220, 220, 220]
            },
            "hp_bar_position": [100, 50],
            "hp_threshold": 30,
            "pickup_key": "z",
            "hp_potion_key": "1",
            "mp_potion_key": "2",
            "skills": {
                "skill_1": {"key": "q", "cooldown": 5},
                "skill_2": {"key": "w", "cooldown": 10},
                "skill_3": {"key": "e", "cooldown": 15}
            },
            "attack_delay": [0.5, 1.0],
            "scan_interval": 0.3,
            "debug_mode": False
        }
        
        if os.path.exists(config_file):
            with open(config_file, 'r', encoding='utf-8') as f:
                loaded_config = json.load(f)
                default_config.update(loaded_config)
        else:
            with open(config_file, 'w', encoding='utf-8') as f:
                json.dump(default_config, f, indent=4)
        
        return default_config
    
    def load_templates(self):
        """Görüntü şablonlarını yükle"""
        template_files = {
            "metin": "templates/metin.png",
            "hp_bar": "templates/hp_bar.png",
            "item": "templates/item.png",
            "mob": "templates/mob.png"
        }
        
        for name, path in template_files.items():
            if os.path.exists(path):
                self.templates[name] = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
            else:
                print(f"Uyarı: {path} bulunamadı")
    
    def find_game_window(self):
        """Oyun penceresini bul ve konumunu al"""
        def enum_windows_callback(hwnd, windows):
            if win32gui.IsWindowVisible(hwnd):
                window_text = win32gui.GetWindowText(hwnd)
                if self.window_title in window_text:
                    windows.append(hwnd)
            return True
        
        windows = []
        win32gui.EnumWindows(enum_windows_callback, windows)
        
        if windows:
            self.window_handle = windows[0]
            rect = win32gui.GetWindowRect(self.window_handle)
            self.window_region = (rect[0], rect[1], rect[2], rect[3])
            print(f"Oyun penceresi bulundu: {self.window_region}")
            return True
        return False
    
    def bring_window_to_front(self):
        """Oyun penceresini öne getir"""
        if self.window_handle:
            win32gui.SetForegroundWindow(self.window_handle)
            time.sleep(0.1)
    
    def capture_screen(self):
        """Oyun ekranını yakala"""
        if self.window_region:
            screenshot = ImageGrab.grab(bbox=self.window_region)
            return cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
        return None
    
    def find_metin_stones(self, screenshot):
        """Metin taşlarını tespit et"""
        # Renk tabanlı tespit
        lower = np.array(self.config["metin_colors"]["lower"])
        upper = np.array(self.config["metin_colors"]["upper"])
        
        mask = cv2.inRange(screenshot, lower, upper)
        
        # Morfolojik işlemler ile gürültüyü azalt
        kernel = np.ones((5, 5), np.uint8)
        mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
        mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
        
        # Konturları bul
        contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        
        metin_positions = []
        for contour in contours:
            area = cv2.contourArea(contour)
            if 1000 < area < 50000:  # Alan filtresi
                # Dikdörtgen kontrolü
                x, y, w, h = cv2.boundingRect(contour)
                aspect_ratio = float(w) / h
                if 0.5 < aspect_ratio < 2.0:  # Metin taşları genelde kareye yakın
                    cx = x + w // 2
                    cy = y + h // 2
                    metin_positions.append({
                        "position": (cx + self.window_region[0], cy + self.window_region[1]),
                        "size": area,
                        "bounds": (x, y, w, h)
                    })
        
        # Template matching ile doğrula (eğer template varsa)
        if "metin" in self.templates and self.templates["metin"] is not None:
            metin_positions = self.verify_with_template(screenshot, metin_positions)
        
        # Mesafeye göre sırala (yakından uzağa)
        center_x = self.config["window_width"] // 2
        center_y = self.config["window_height"] // 2
        metin_positions.sort(key=lambda m: 
            ((m["position"][0] - center_x - self.window_region[0])**2 + 
             (m["position"][1] - center_y - self.window_region[1])**2)**0.5
        )
        
        return metin_positions
    
    def verify_with_template(self, screenshot, positions):
        """Template matching ile pozisyonları doğrula"""
        gray = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)
        template = self.templates["metin"]
        
        verified = []
        for metin in positions:
            x, y, w, h = metin["bounds"]
            roi = gray[max(0, y-20):min(gray.shape[0], y+h+20), 
                      max(0, x-20):min(gray.shape[1], x+w+20)]
            
            if roi.size > 0:
                result = cv2.matchTemplate(roi, template, cv2.TM_CCOEFF_NORMED)
                if result.max() > 0.6:
                    verified.append(metin)
        
        return verified if verified else positions
    
    def check_hp(self, screenshot):
        """HP kontrolü yap"""
        # Basit renk tabanlı HP kontrolü
        hp_region = screenshot[
            self.config["hp_bar_position"][1]:self.config["hp_bar_position"][1]+20,
            self.config["hp_bar_position"][0]:self.config["hp_bar_position"][0]+200
        ]
        
        # Kırmızı pikselleri say
        red_pixels = cv2.inRange(hp_region, np.array([0, 0, 150]), np.array([50, 50, 255]))
        hp_percentage = (cv2.countNonZero(red_pixels) / red_pixels.size) * 100
        
        return hp_percentage
    
    def use_potion(self, potion_type="hp"):
        """Pot kullan"""
        key = self.config["hp_potion_key"] if potion_type == "hp" else self.config["mp_potion_key"]
        pyautogui.press(key)
        print(f"{potion_type.upper()} potu kullanıldı")
    
    def attack_target(self, target):
        """Hedefe saldır"""
        x, y = target["position"]
        
        # Hedefi tıkla
        pyautogui.click(x, y, button='left')
        self.stats["total_clicks"] += 1
        
        # Rastgele gecikme
        delay = random.uniform(*self.config["attack_delay"])
        time.sleep(delay)
        
        # Skill kullan
        self.use_skills()
    
    def use_skills(self):
        """Becerileri kullan"""
        current_time = time.time()
        
        for skill_name, skill_info in self.config["skills"].items():
            if current_time - self.last_skill_time > skill_info["cooldown"]:
                pyautogui.press(skill_info["key"])
                self.last_skill_time = current_time
                if self.config["debug_mode"]:
                    print(f"{skill_name} kullanıldı")
                break
    
    def pickup_items(self):
        """Yerdeki itemleri topla"""
        pyautogui.press(self.config["pickup_key"])
        self.stats["items_picked"] += 1
        if self.config["debug_mode"]:
            print("Item toplandı")
    
    def find_items_on_ground(self, screenshot):
        """Yerdeki itemleri tespit et"""
        # Parlak itemler için renk tespiti
        hsv = cv2.cvtColor(screenshot, cv2.COLOR_BGR2HSV)
        
        # Parlak renk aralığı
        lower_bright = np.array([0, 0, 200])
        upper_bright = np.array([255, 30, 255])
        
        mask = cv2.inRange(hsv, lower_bright, upper_bright)
        contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        
        items = []
        for contour in contours:
            area = cv2.contourArea(contour)
            if 50 < area < 1000:  # Küçük parlak alanlar
                M = cv2.moments(contour)
                if M["m00"] != 0:
                    cx = int(M["m10"] / M["m00"])
                    cy = int(M["m01"] / M["m00"])
                    items.append((cx, cy))
        
        return items
    
    def is_target_alive(self, target_pos):
        """Hedefin hala var olup olmadığını kontrol et"""
        screenshot = self.capture_screen()
        if screenshot is None:
            return False
        
        # Hedef bölgesini kontrol et
        x, y = target_pos["position"]
        x -= self.window_region[0]
        y -= self.window_region[1]
        
        roi_size = 50
        roi = screenshot[
            max(0, y-roi_size):min(screenshot.shape[0], y+roi_size),
            max(0, x-roi_size):min(screenshot.shape[1], x+roi_size)
        ]
        
        # Hedefin rengini kontrol et
        lower = np.array(self.config["metin_colors"]["lower"])
        upper = np.array(self.config["metin_colors"]["upper"])
        mask = cv2.inRange(roi, lower, upper)
        
        return cv2.countNonZero(mask) > 100
    
    def main_loop(self):
        """Ana bot döngüsü"""
        print("Bot başlatıldı.")
        print("Komutlar:")
        print("  P - Duraklat/Devam et")
        print("  Q - Çıkış")
        print("  S - İstatistikleri göster")
        
        self.stats["start_time"] = datetime.now()
        
        while self.running:
            try:
                if self.paused:
                    time.sleep(0.1)
                    continue
                
                # Ekran görüntüsü al
                screenshot = self.capture_screen()
                if screenshot is None:
                    print("Oyun penceresi bulunamadı, tekrar arıyor...")
                    if self.find_game_window():
                        self.bring_window_to_front()
                    time.sleep(1)
                    continue
                
                # HP kontrolü
                current_time = time.time()
                if current_time - self.last_hp_check > 1:
                    hp = self.check_hp(screenshot)
                    if hp < self.config["hp_threshold"]:
                        self.use_potion("hp")
                    self.last_hp_check = current_time
                
                # Mevcut hedef kontrolü
                if self.current_target and self.attack_mode:
                    if self.is_target_alive(self.current_target):
                        self.attack_target(self.current_target)
                        continue
                    else:
                        print("Metin taşı yok edildi!")
                        self.stats["metin_destroyed"] += 1
                        self.current_target = None
                        self.attack_mode = False
                        
                        # Item toplama zamanı
                        for _ in range(3):
                            self.pickup_items()
                            time.sleep(0.5)
                
                # Yeni metin taşı ara
                metin_stones = self.find_metin_stones(screenshot)
                
                if metin_stones:
                    self.current_target = metin_stones[0]
                    self.attack_mode = True
                    print(f"Yeni hedef: {self.current_target['position']}")
                else:
                    # Item toplama kontrolü
                    if current_time - self.last_pickup_time >= self.pickup_interval:
                        items = self.find_items_on_ground(screenshot)
                        if items or random.random() < 0.3:  # %30 şans ile de topla
                            self.pickup_items()
                            self.last_pickup_time = current_time
                            self.pickup_interval = random.uniform(5, 10)
                
                # Debug modu
                if self.config["debug_mode"]:
                    self.draw_debug_info(screenshot, metin_stones)
                
                # Döngü gecikmesi
                time.sleep(self.config["scan_interval"])
                
            except Exception as e:
                print(f"Hata: {e}")
                import traceback
                traceback.print_exc()
                time.sleep(1)
    
    def draw_debug_info(self, screenshot, metin_stones):
        """Debug bilgilerini göster"""
        debug_img = screenshot.copy()
        
        # Metin taşlarını işaretle
        for metin in metin_stones:
            x, y, w, h = metin["bounds"]
            cv2.rectangle(debug_img, (x, y), (x+w, y+h), (0, 255, 0), 2)
            cv2.putText(debug_img, f"Size: {metin['size']}", 
                       (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
        
        # Debug penceresini göster
        cv2.imshow("Bot Debug", debug_img)
        cv2.waitKey(1)
    
    def show_stats(self):
        """İstatistikleri göster"""
        if self.stats["start_time"]:
            runtime = datetime.now() - self.stats["start_time"]
            print("\n=== Bot İstatistikleri ===")
            print(f"Çalışma Süresi: {runtime}")
            print(f"Yok Edilen Metin: {self.stats['metin_destroyed']}")
            print(f"Toplanan Item: {self.stats['items_picked']}")
            print(f"Toplam Tıklama: {self.stats['total_clicks']}")
            print(f"Metin/Saat: {self.stats['metin_destroyed'] / (runtime.seconds / 3600):.2f}")
            print("========================\n")
    
    def save_stats(self):
        """İstatistikleri dosyaya kaydet"""
        stats_file = f"bot_stats_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
        with open(stats_file, 'w', encoding='utf-8') as f:
            stats_copy = self.stats.copy()
            stats_copy["start_time"] = str(stats_copy["start_time"])
            stats_copy["end_time"] = str(datetime.now())
            json.dump(stats_copy, f, indent=4)
        print(f"İstatistikler kaydedildi: {stats_file}")
    
    def keyboard_handler(self):
        """Klavye komutlarını dinle"""
        while self.running:
            if keyboard.is_pressed('q'):
                self.stop()
                break
            elif keyboard.is_pressed('p'):
                self.paused = not self.paused
                status = "duraklatıldı" if self.paused else "devam ediyor"
                print(f"Bot {status}")
                time.sleep(0.5)
            elif keyboard.is_pressed('s'):
                self.show_stats()
                time.sleep(0.5)
            time.sleep(0.1)
    
    def start(self):
        """Botu başlat"""
        print("Oyun penceresi aranıyor...")
        if not self.find_game_window():
            print(f"'{self.window_title}' penceresi bulunamadı!")
            return
        
        self.bring_window_to_front()
        self.running = True
        
        # Thread'leri başlat
        bot_thread = threading.Thread(target=self.main_loop)
        keyboard_thread = threading.Thread(target=self.keyboard_handler)
        
        bot_thread.start()
        keyboard_thread.start()
        
        bot_thread.join()
        keyboard_thread.join()
    
    def stop(self):
        """Botu durdur"""
        self.running = False
        self.show_stats()
        self.save_stats()
        cv2.destroyAllWindows()
        print("Bot durduruldu.")

# Gelişmiş özellikler için ek sınıf
class Metin2BotAdvanced(Metin2Bot):
    def __init__(self, config_file="bot_config.json"):
        super().__init__(config_file)
        
        # Ek özellikler
        self.mob_detection = True
        self.auto_buff = True
        self.path_memory = []
        self.danger_zones = []
        
    def detect_mobs(self, screenshot):
        """Yakındaki mobları tespit et"""
        # Mob tespiti için HSV renk aralığı
        hsv = cv2.cvtColor(screenshot, cv2.COLOR_BGR2HSV)
        
        # Kırmızı isim rengi (düşman moblar)
        lower_red = np.array([0, 100, 100])
        upper_red = np.array([10, 255, 255])
        mask1 = cv2.inRange(hsv, lower_red, upper_red)
        
        lower_red2 = np.array([170, 100, 100])
        upper_red2 = np.array([180, 255, 255])
        mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
        
        mask = cv2.bitwise_or(mask1, mask2)
        
        # Mob pozisyonlarını bul
        contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        
        mobs = []
        for contour in contours:
            area = cv2.contourArea(contour)
            if 50 < area < 500:  # İsim etiketi boyutu
                x, y, w, h = cv2.boundingRect(contour)
                mobs.append({
                    "position": (x + w//2, y + h//2),
                    "danger_level": self.calculate_danger(x, y)
                })
        
        return mobs
    
    def calculate_danger(self, x, y):
        """Tehlike seviyesini hesapla"""
        center_x = self.config["window_width"] // 2
        center_y = self.config["window_height"] // 2
        distance = ((x - center_x)**2 + (y - center_y)**2)**0.5
        
        if distance < 100:
            return "high"
        elif distance < 200:
            return "medium"
        else:
            return "low"
    
    def auto_buff_check(self):
        """Otomatik buff kontrolü"""
        buff_schedule = {
            "aura": {"key": "g", "interval": 300},  # 5 dakika
            "berserk": {"key": "h", "interval": 120}  # 2 dakika
        }
        
        current_time = time.time()
        for buff_name, buff_info in buff_schedule.items():
            last_used = getattr(self, f"last_{buff_name}_time", 0)
            if current_time - last_used > buff_info["interval"]:
                pyautogui.press(buff_info["key"])
                setattr(self, f"last_{buff_name}_time", current_time)
                print(f"{buff_name} buff'ı yenilendi")

# Ana program
if __name__ == "__main__":
    print("Metin2 Bot v2.0")
    print("1. Normal Bot")
    print("2. Gelişmiş Bot")
    
    choice = input("Seçiminiz (1/2): ")
    
    if choice == "2":
        bot = Metin2BotAdvanced()
    else:
        bot = Metin2Bot()
    
    print("\nBot 3 saniye içinde başlayacak...")
    print("Oyunun 1600x900 pencere modunda açık olduğundan emin olun!")
    time.sleep(3)
    
    bot.start()
şu kodu dene bakalım gereken ksıımları kendine göre düzenle.