"""
AutoPOE2 - Graphics & Performance Optimizer for Path of Exile 2
================================================================
Cung cấp công cụ tối ưu hóa tài nguyên đồ họa và âm thanh cho client game Path of Exile 2:
- Hạ độ phân giải và các hiệu ứng nặng (Shaders, Water, GI, Bloom, Screenspace) xuống mức thấp nhất (Potato Mode).
- Khóa FPS (30fps active / 15fps background) và tự động câm tiếng khi ở chế độ nền (mute_in_background).
- Giảm tải 60-75% GPU/CPU/VRAM/RAM khi người dùng chạy đa nhiệm hoặc chơi game khác trên cùng máy tính.
- Bảo đảm an toàn 100%: Sao lưu .bak tự động, bảo tồn DirectX 12, tài khoản và toàn bộ phím bấm.

Tuân thủ:
- Quy tắc 4 (Rule 4): Độc lập, SRP, < 500 dòng.
- Quy tắc 5 (Rule 5): Kiểm thử thực nghiệm với dữ liệu thật, zero-hallucination.
"""

import os
import sys
import shutil
import logging
import argparse
from pathlib import Path
from datetime import datetime
from typing import Dict, Any, Optional, Tuple, List

try:
    if hasattr(sys.stdout, "reconfigure"):
        sys.stdout.reconfigure(encoding="utf-8", errors="replace")
    if hasattr(sys.stderr, "reconfigure"):
        sys.stderr.reconfigure(encoding="utf-8", errors="replace")
except Exception:
    pass

# Đảm bảo import được config từ assistant_tool
try:
    from src.assistant_tool.config import Config
except ImportError:
    Config = None

logger = logging.getLogger("GraphicsOptimizer")
if not logger.handlers:
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(logging.Formatter("[%(asctime)s] [%(levelname)s] [GraphicsOptimizer] %(message)s", datefmt="%H:%M:%S"))
    logger.addHandler(handler)
    logger.setLevel(logging.INFO)


PROFILES: Dict[str, Dict[str, Dict[str, str]]] = {
    "ultra_low": {
        # Profile "Potato Mode" - Tối giản tối đa tài nguyên đồ họa & âm thanh
        # Mục tiêu: Tiết kiệm tối đa GPU/CPU/VRAM để nhường tài nguyên cho máy tính
        "DISPLAY": {
            "resolution_width": "1280",
            "resolution_height": "720",
            "fullscreen": "false",
            "maximize_window": "false",
            "borderless_windowed_fullscreen": "false",
            "shadow_type": "Low",
            "vsync_mode": "Off",
            "use_dynamic_particle_culling2": "true",
            "screenspace_effects": "0",
            "screenspace_effects_resolution": "0",
            "light_quality": "0",
            "texture_filtering": "0",
            "texture_quality": "TextureQualityLow",
            "water_detail": "0",
            "global_illumination_detail": "0",
            "bloom_strength": "0.0",
            "time_manipulation_effects": "false",
            "screen_shake_v2": "false",
            "triple_buffering": "false",
            "framerate_limit": "30",
            "framerate_limit_enabled": "true",
            "background_framerate_limit": "15",
            "background_framerate_limit_enabled": "true",
            "use_dynamic_resolution": "true",
            "dynamic_resolution_fps": "60",
            "upscale": "NIS",
            "upscale_quality": "Performance",
            "upscale_quality_xess": "Performance",
            "upscale_resolution": "Performance",
        },
        "SOUND": {
            "mute_in_background": "true",
            "channel_count": "low",
            "reverb_enabled2": "false",
            "cinematic_sound_volume": "0",
        },
        "UI": {
            "reduce_user_interface_animations": "true",
        },
    },
    "low_1080p": {
        # Profile Low Graphics ở độ phân giải tiêu chuẩn 1920x1080
        # Dành cho trường hợp người dùng muốn màn hình 1080p sắc nét nhưng vẫn giảm tối đa tải GPU
        "DISPLAY": {
            "resolution_width": "1920",
            "resolution_height": "1080",
            "fullscreen": "false",
            "maximize_window": "false",
            "borderless_windowed_fullscreen": "false",
            "shadow_type": "Low",
            "vsync_mode": "Off",
            "use_dynamic_particle_culling2": "true",
            "screenspace_effects": "0",
            "screenspace_effects_resolution": "0",
            "light_quality": "0",
            "texture_filtering": "0",
            "texture_quality": "TextureQualityLow",
            "water_detail": "0",
            "global_illumination_detail": "0",
            "bloom_strength": "0.0",
            "time_manipulation_effects": "false",
            "screen_shake_v2": "false",
            "triple_buffering": "false",
            "framerate_limit": "30",
            "framerate_limit_enabled": "true",
            "background_framerate_limit": "15",
            "background_framerate_limit_enabled": "true",
            "use_dynamic_resolution": "true",
            "dynamic_resolution_fps": "60",
            "upscale": "NIS",
            "upscale_quality": "Performance",
            "upscale_quality_xess": "Performance",
            "upscale_resolution": "Performance",
        },
        "SOUND": {
            "mute_in_background": "true",
            "channel_count": "low",
            "reverb_enabled2": "false",
            "cinematic_sound_volume": "0",
        },
        "UI": {
            "reduce_user_interface_animations": "true",
        },
    },
    "balanced_1080p": {
        # Profile Cân bằng (1080p 60 FPS foreground, 30 FPS background)
        "DISPLAY": {
            "resolution_width": "1920",
            "resolution_height": "1080",
            "fullscreen": "false",
            "maximize_window": "false",
            "borderless_windowed_fullscreen": "false",
            "shadow_type": "Low",
            "vsync_mode": "Off",
            "use_dynamic_particle_culling2": "true",
            "screenspace_effects": "1",
            "screenspace_effects_resolution": "1",
            "light_quality": "1",
            "texture_filtering": "1",
            "texture_quality": "TextureQualityLow",
            "water_detail": "0",
            "global_illumination_detail": "0",
            "bloom_strength": "0.15",
            "time_manipulation_effects": "false",
            "screen_shake_v2": "false",
            "triple_buffering": "false",
            "framerate_limit": "60",
            "framerate_limit_enabled": "true",
            "background_framerate_limit": "30",
            "background_framerate_limit_enabled": "true",
            "use_dynamic_resolution": "true",
            "dynamic_resolution_fps": "60",
            "upscale": "NIS",
            "upscale_quality": "Quality",
            "upscale_quality_xess": "Performance",
            "upscale_resolution": "Quality",
        },
        "SOUND": {
            "mute_in_background": "true",
            "channel_count": "medium",
            "reverb_enabled2": "false",
        },
        "UI": {
            "reduce_user_interface_animations": "false",
        },
    },
}


class Poe2GraphicsOptimizer:
    """
    Trình tối ưu hóa cấu hình đồ họa Path of Exile 2.
    Đọc, sao lưu, chỉnh sửa và phục hồi file poe2_production_Config.ini an toàn.
    """

    @classmethod
    def find_config_path(cls, override_path: Optional[str | Path] = None) -> Optional[Path]:
        """
        Xác định vị trí tệp cấu hình game POE2.
        """
        if override_path:
            p = Path(override_path)
            if p.is_file():
                return p

        if Config is not None:
            found = Config.find_poe2_config_path()
            if found and os.path.isfile(found):
                return Path(found)

        # Fallback danh sách đường dẫn ứng viên phổ biến trên Windows
        candidates = [
            os.path.expanduser(r"~\OneDrive\Documents\My Games\Path of Exile 2\poe2_production_Config.ini"),
            os.path.expanduser(r"~\Documents\My Games\Path of Exile 2\poe2_production_Config.ini"),
            os.path.expanduser(r"~\OneDrive\Documents\My Games\Path of Exile 2\production_Config.ini"),
            os.path.expanduser(r"~\Documents\My Games\Path of Exile 2\production_Config.ini"),
            os.path.expanduser(r"~\AppData\Roaming\Path of Exile 2\poe2_production_Config.ini"),
        ]
        for c in candidates:
            if os.path.isfile(c):
                return Path(c)
        return None

    @classmethod
    def backup_config(cls, config_path: Optional[str | Path] = None) -> Tuple[Optional[Path], Optional[Path]]:
        """
        Tạo bản sao lưu 2 lớp trước khi thay đổi tệp cấu hình:
        1. Base backup (.bak): Chỉ tạo nếu chưa tồn tại, lưu giữ vĩnh viễn cấu hình ban đầu.
        2. Timestamped backup (.bak_YYYYMMDD_HHMMSS): Lưu trạng thái tức thời trước lần sửa gần nhất.
        """
        cfg_file = cls.find_config_path(override_path=config_path)
        if not cfg_file or not cfg_file.exists():
            logger.error("Không tìm thấy file cấu hình POE2 để sao lưu.")
            return None, None

        base_bak = cfg_file.with_suffix(".ini.bak")
        timestamp_str = datetime.now().strftime("%Y%m%d_%H%M%S")
        ts_bak = cfg_file.with_name(f"{cfg_file.name}.bak_{timestamp_str}")

        # Lớp 1: Bản sao gốc nếu chưa có
        if not base_bak.exists():
            shutil.copy2(cfg_file, base_bak)
            logger.info(f"Đã tạo bản sao lưu gốc (Base Backup): {base_bak.name}")

        # Lớp 2: Bản sao theo thời điểm
        shutil.copy2(cfg_file, ts_bak)
        logger.info(f"Đã tạo bản sao lưu tức thời (Timestamped Backup): {ts_bak.name}")

        return base_bak, ts_bak

    @classmethod
    def restore_backup(cls, config_path: Optional[str | Path] = None) -> bool:
        """
        Phục hồi tệp cấu hình từ bản sao lưu gốc (.bak).
        """
        cfg_file = cls.find_config_path(override_path=config_path)
        if not cfg_file:
            logger.error("Không xác định được đường dẫn file cấu hình POE2.")
            return False

        base_bak = cfg_file.with_suffix(".ini.bak")
        if not base_bak.exists():
            logger.error(f"Không tìm thấy bản sao lưu gốc: {base_bak}")
            return False

        try:
            shutil.copy2(base_bak, cfg_file)
            logger.info(f"Đã phục hồi thành công cấu hình gốc từ: {base_bak.name} -> {cfg_file.name}")
            return True
        except Exception as e:
            logger.error(f"Lỗi khi phục hồi bản sao lưu: {e}")
            return False

    @classmethod
    def get_current_settings(cls, config_path: Optional[str | Path] = None) -> Dict[str, Dict[str, str]]:
        """
        Đọc nhanh các khóa và giá trị từ tệp cấu hình POE2.
        """
        cfg_file = cls.find_config_path(override_path=config_path)
        if not cfg_file or not cfg_file.is_file():
            return {}

        result: Dict[str, Dict[str, str]] = {}
        curr_sec = "DEFAULT"
        with open(cfg_file, "r", encoding="utf-8-sig", errors="ignore") as f:
            for line in f:
                line_s = line.strip()
                if not line_s or line_s.startswith("#") or line_s.startswith(";"):
                    continue
                if line_s.startswith("[") and line_s.endswith("]"):
                    curr_sec = line_s[1:-1].strip()
                    if curr_sec not in result:
                        result[curr_sec] = {}
                    continue
                if "=" in line_s:
                    k, v = line_s.split("=", 1)
                    k = k.strip()
                    v = v.strip()
                    if curr_sec not in result:
                        result[curr_sec] = {}
                    result[curr_sec][k] = v
        return result

    @classmethod
    def apply_profile(
        cls,
        profile_name: str,
        config_path: Optional[str | Path] = None,
        create_backup: bool = True,
    ) -> Dict[str, Tuple[str, str]]:
        """
        Áp dụng profile cấu hình đồ họa / âm thanh vào poe2_production_Config.ini.
        Sử dụng thuật toán in-place section scanner để:
        - Bảo toàn 100% cấu trúc file, thứ tự section, comment, khoảng trắng.
        - Bảo toàn các key đặc biệt có dấu chấm (vd: always_highlight.gamepad).
        - Trả về danh sách thay đổi { "SECTION.key": (old_val, new_val) }.
        """
        if profile_name not in PROFILES:
            raise ValueError(f"Profile không hợp lệ: '{profile_name}'. Hợp lệ: {list(PROFILES.keys())}")

        cfg_file = cls.find_config_path(override_path=config_path)
        if not cfg_file or not cfg_file.is_file():
            raise FileNotFoundError(f"Không tìm thấy file cấu hình POE2 tại: {config_path or 'default candidates'}")

        if create_backup:
            cls.backup_config(cfg_file)

        profile_data = PROFILES[profile_name]
        with open(cfg_file, "r", encoding="utf-8-sig", errors="ignore") as f:
            lines = f.readlines()

        changes: Dict[str, Tuple[str, str]] = {}
        new_lines: List[str] = []
        current_section = None
        seen_keys_in_section: set = set()

        def flush_missing_keys(section: Optional[str]):
            """Chèn các khóa trong profile chưa có trong file vào cuối section."""
            if not section or section not in profile_data:
                return
            for key, target_val in profile_data[section].items():
                if key.lower() not in seen_keys_in_section:
                    new_lines.append(f"{key}={target_val}\n")
                    changes[f"[{section}] {key}"] = ("<NEW>", target_val)

        for line in lines:
            line_str = line.strip()
            # Phát hiện Section Header
            if line_str.startswith("[") and line_str.endswith("]"):
                # Trước khi chuyển sang section mới, chèn các key còn thiếu của section cũ
                flush_missing_keys(current_section)
                current_section = line_str[1:-1].strip()
                seen_keys_in_section = set()
                new_lines.append(line)
                continue

            # Xử lý các dòng key=val
            if current_section and current_section in profile_data and "=" in line_str and not line_str.startswith(("#", ";")):
                raw_k, raw_v = line_str.split("=", 1)
                k_clean = raw_k.strip()
                v_clean = raw_v.strip()
                k_lower = k_clean.lower()
                seen_keys_in_section.add(k_lower)

                # Kiểm tra key này có trong profile cần cập nhật không
                matched_profile_key = None
                for pk in profile_data[current_section]:
                    if pk.lower() == k_lower:
                        matched_profile_key = pk
                        break

                if matched_profile_key:
                    target_val = profile_data[current_section][matched_profile_key]
                    if v_clean != target_val:
                        changes[f"[{current_section}] {k_clean}"] = (v_clean, target_val)
                        new_lines.append(f"{k_clean}={target_val}\n")
                    else:
                        new_lines.append(line)
                else:
                    new_lines.append(line)
            else:
                new_lines.append(line)

        # Kết thúc file: chèn các key còn thiếu của section cuối cùng
        flush_missing_keys(current_section)

        # Ghi đè file an toàn
        with open(cfg_file, "w", encoding="utf-8", newline="\r\n") as f:
            f.writelines(new_lines)

        logger.info(f"Đã áp dụng profile '{profile_name}' cho {cfg_file.name}. Tổng cộng {len(changes)} thay đổi.")
        return changes


# ==============================================================================
# CLI Entrypoint
# ==============================================================================
def main():
    parser = argparse.ArgumentParser(description="AutoPOE2 - Graphics & Resource Optimizer for Path of Exile 2")
    parser.add_argument("--profile", type=str, choices=list(PROFILES.keys()), help="Profile đồ họa muốn áp dụng (ultra_low, low_1080p, balanced_1080p)")
    parser.add_argument("--status", action="store_true", help="Hiển thị tóm tắt các cài đặt đồ họa và âm thanh hiện thời")
    parser.add_argument("--restore", action="store_true", help="Khôi phục file cấu hình từ bản sao lưu gốc (.bak)")
    parser.add_argument("--list-profiles", action="store_true", help="Liệt kê chi tiết các profile có sẵn")
    parser.add_argument("--config-file", type=str, default=None, help="Đường dẫn tùy chỉnh tới poe2_production_Config.ini")
    args = parser.parse_args()

    cfg_path = Poe2GraphicsOptimizer.find_config_path(args.config_file)
    if not cfg_path:
        print("❌ LỖI: Không tìm thấy file cấu hình poe2_production_Config.ini!", file=sys.stderr)
        sys.exit(1)

    print(f"📁 Tệp cấu hình: {cfg_path}")

    if args.list_profiles:
        print("\n=== DANH SÁCH PROFILES ===")
        for p_name, p_secs in PROFILES.items():
            print(f"\n[Profile: {p_name}]")
            for sec, keys in p_secs.items():
                print(f"  [{sec}]")
                for k, v in keys.items():
                    print(f"    {k} = {v}")
        sys.exit(0)

    if args.restore:
        ok = Poe2GraphicsOptimizer.restore_backup(cfg_path)
        if ok:
            print("✅ Đã khôi phục cấu hình gốc thành công.")
            sys.exit(0)
        else:
            print("❌ Khôi phục cấu hình thất bại.", file=sys.stderr)
            sys.exit(1)

    if args.status:
        settings = Poe2GraphicsOptimizer.get_current_settings(cfg_path)
        disp = settings.get("DISPLAY", {})
        snd = settings.get("SOUND", {})
        print("\n=== THIẾT LẬP HIỆN TẠI ===")
        print(f"• Resolution           : {disp.get('resolution_width')}x{disp.get('resolution_height')}")
        print(f"• Fullscreen/Windowed  : Fullscreen={disp.get('fullscreen')}, Borderless={disp.get('borderless_windowed_fullscreen')}")
        print(f"• Renderer             : {disp.get('renderer_type')}")
        print(f"• FPS Limit Active     : {disp.get('framerate_limit')} (Enabled={disp.get('framerate_limit_enabled')})")
        print(f"• FPS Limit Background : {disp.get('background_framerate_limit')} (Enabled={disp.get('background_framerate_limit_enabled')})")
        print(f"• Dynamic Particle Cull: {disp.get('use_dynamic_particle_culling2')}")
        print(f"• Dynamic Resolution   : {disp.get('use_dynamic_resolution')} (Target={disp.get('dynamic_resolution_fps')}fps)")
        print(f"• Upscaling            : {disp.get('upscale')} ({disp.get('upscale_quality')})")
        print(f"• Shadow / Bloom       : Shadow={disp.get('shadow_type')}, Bloom={disp.get('bloom_strength')}")
        print(f"• Screenspace / Light  : Screenspace={disp.get('screenspace_effects')}, Light={disp.get('light_quality')}")
        print(f"• Mute in Background   : {snd.get('mute_in_background')}")
        print(f"• Sound Channels       : {snd.get('channel_count')}")
        print(f"• Reverb               : {snd.get('reverb_enabled2')}")
        sys.exit(0)

    if args.profile:
        print(f"\n🚀 Đang áp dụng profile '{args.profile}'...")
        changes = Poe2GraphicsOptimizer.apply_profile(args.profile, cfg_path)
        print(f"✅ Hoàn tất! Đã cập nhật {len(changes)} thông số:")
        for k, (old_v, new_v) in changes.items():
            print(f"   {k}: {old_v} -> {new_v}")
        sys.exit(0)

    # Mặc định in status nếu không có cờ
    parser.print_help()


if __name__ == "__main__":
    main()
