"""AutoPOE2 - Stage 0 Stash Logistics & Auto Waystone Withdrawal (Doc 61 / Doc 63 / Doc 69).
==========================================================================================
Điều phối khép kín quy trình hậu cần Stash tại Hideout:
1. INV-FOCUS-SAFETY-SEPARATION: Bảo đảm an toàn tuyệt đối, trong mock/simulation cấm gửi Win32 events ra desktop.
2. INV-KEY-NO-F-FOR-INTERACT: Tiếp cận và click LMB mở Stash tại Hideout, tuyệt đối cấm phím F.
3. INV-STASH-CTRL-CLICK: Cất đồ nhặt từ map (Loot Deposit) qua Ctrl+Click có jitter 180ms ± 40ms.
4. INV-WAYSTONE-ROW1-ONLY & INV-WAYSTONE-RESTOCK-MIN: Rút bổ sung Waystone T15 từ Stash Map Tab (Tier XV)
   vào Hàng 1 của túi đồ khi số lượng Waystone hiện tại < keep_waystones_count (mặc định 5).
5. INV-SPACEBAR-CLOSE: Đóng Stash an toàn bằng Spacebar trước khi chuyển sang Stage 1 hoặc kết thúc.
6. Rule 4: Tách biệt module chuyên trách, giữ file điều phối chính < 500 dòng (Anti-Monolithic).
"""

from __future__ import annotations

import random
import time
from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Tuple, Union

try:
    from PIL import Image
except ImportError:
    Image = None  # type: ignore[assignment]

from src.assistant_tool.stash.stash_constants import (
    StashAction,
    StashConfig,
    StashTabType,
)
from src.assistant_tool.stash.stash_orchestrator import StashOrchestrator
from src.assistant_tool.stash.stash_ui_scanner import StashTabInfo
from src.common.win32_input import set_input_simulation_mode


@dataclass
class Stage0Result:
    """Báo cáo kết quả thực thi Stage 0: Stash Logistics & Restock."""
    status: str = "FAILED"  # "SUCCESS", "FAILED", "SKIPPED"
    stash_opened: bool = False
    tabs_detected: int = 0
    items_deposited: int = 0
    waystone_withdrawn: bool = False
    waystones_withdrawn_count: int = 0
    current_waystones_in_bag: int = 0
    target_tier: int = 15
    stash_closed: bool = False
    error: str = ""
    phase: str = "pre_map"  # "pre_map" | "post_map"

    def to_dict(self) -> Dict[str, Any]:
        return {
            "status": self.status,
            "stash_opened": self.stash_opened,
            "tabs_detected": self.tabs_detected,
            "items_deposited": self.items_deposited,
            "waystone_withdrawn": self.waystone_withdrawn,
            "waystones_withdrawn_count": self.waystones_withdrawn_count,
            "current_waystones_in_bag": self.current_waystones_in_bag,
            "target_tier": self.target_tier,
            "stash_closed": self.stash_closed,
            "error": self.error,
            "phase": self.phase,
        }


class Stage0StashHandler:
    """
    Module bổ trợ chuyên trách Stage 0: Stash Logistics & Auto Waystone Withdrawal (Doc 61/63/69).
    Tuân thủ nghiêm ngặt các bất biến:
    - INV-FOCUS-SAFETY-SEPARATION: Tuyệt đối không gửi Win32 key/mouse events khi is_simulated=True.
    - INV-KEY-NO-F-FOR-INTERACT: Mở Stash bằng LMB click tuyệt đối, cấm phím F.
    - INV-STASH-CTRL-CLICK: Cất đồ qua Ctrl+Click có jitter 180ms ± 40ms.
    - INV-WAYSTONE-ROW1-ONLY: Rút Waystone T15 từ Stash Map Tab nạp vào Hàng 1 túi đồ.
    - INV-SPACEBAR-CLOSE: Đóng Stash bằng phím Spacebar.
    """

    def __init__(
        self,
        screen_w: int = 2560,
        screen_h: int = 1440,
        config: Optional[StashConfig] = None,
        orchestrator: Optional[StashOrchestrator] = None,
        is_simulated: bool = False,
        target_waystone_tier: int = 15,
        target_waystone_count: int = 5,
        log_callback: Optional[Callable[[str], None]] = None,
    ):
        self.screen_w = screen_w
        self.screen_h = screen_h
        self.config = config or StashConfig()
        self.is_simulated = is_simulated
        self.target_waystone_tier = target_waystone_tier
        self.target_waystone_count = target_waystone_count
        self.log_callback = log_callback

        self.orchestrator = orchestrator or StashOrchestrator(
            screen_w=self.screen_w,
            screen_h=self.screen_h,
            config=self.config,
            is_simulated=self.is_simulated,
        )
        if hasattr(self.orchestrator, "is_simulated"):
            self.orchestrator.is_simulated = self.is_simulated

    def log(self, msg: str) -> None:
        if self.log_callback:
            self.log_callback(msg)
        else:
            print(f"[Stage0Stash] {msg}", flush=True)

    def count_waystones_in_inventory(
        self,
        coordinator: Optional[Any] = None,
        img: Optional[Image.Image] = None,
    ) -> int:
        """Đếm số lượng Waystone hiện có trong túi đồ (ưu tiên Hàng 1 per INV-WAYSTONE-ROW1-ONLY)."""
        # 1. Thử qua coordinator.scanner nếu có
        if coordinator and hasattr(coordinator, "scanner") and coordinator.scanner:
            try:
                if img is not None:
                    waystones = coordinator.scanner.scan_all_waystones(img)
                    return len(waystones)
                if hasattr(coordinator.scanner, "memory_reader") and coordinator.scanner.memory_reader:
                    return coordinator.scanner.memory_reader.get_waystones_count()
            except Exception:
                pass

        # 2. Thử qua memory_reader của orchestrator
        if hasattr(self.orchestrator, "matrix") and self.orchestrator.matrix.memory_reader:
            try:
                ram_cnt = self.orchestrator.matrix.memory_reader.get_waystones_count()
                if ram_cnt > 0:
                    return ram_cnt
            except Exception:
                pass

        return 0

    def withdraw_waystone_t15(
        self,
        needed: int,
        img: Optional[Image.Image] = None,
    ) -> Tuple[bool, int]:
        """
        Rút bổ sung Waystone Tier 15 từ Tab Map/Waystone trong Stash (Doc 63).
        Trả về (success, count_withdrawn).
        """
        if needed <= 0:
            return True, 0

        self.log(f"⚡ Cần rút {needed} Waystone Tier {self.target_waystone_tier} từ Stash...")
        success = self.orchestrator.withdraw_waystone_if_needed(
            img=img,
            current_waystones_in_bag=max(0, self.target_waystone_count - needed),
        )
        count_withdrawn = needed if success else 0
        return success, count_withdrawn

    def check_and_recover_stuck_cursor(
        self,
        coordinator: Optional[Any] = None,
        img_path: Optional[str] = None,
    ) -> bool:
        """
        Khóa an toàn con trỏ chuột (Cursor Stuck Recovery Guard):
        Kiểm tra và hoàn trả vật phẩm nếu bị dính vào chuột sau chuỗi Ctrl+Click nhanh (INV-CURSOR-SAFETY).
        Ngăn chặn 100% rủi ro đánh rơi vật phẩm ra sàn Hideout khi đóng Stash.
        """
        if self.is_simulated:
            return False

        check_path = img_path
        if not check_path and coordinator and hasattr(coordinator, "capture_step"):
            check_path = coordinator.capture_step("STASH_CURSOR_CHECK", capture_ram=False)

        try:
            from src.assistant_tool.waystone_loader_guard import WaystoneLoaderGuard
            if check_path and WaystoneLoaderGuard.is_item_stuck_on_cursor(check_path):
                self.log("⚠️ [CURSOR_STUCK_GUARD] Phát hiện vật phẩm dính chuột! Đang giải phóng về túi đồ...")
                scale_x = self.screen_w / 2560.0
                scale_y = self.screen_h / 1440.0
                safe_slot_x = int(1731 * scale_x)
                safe_slot_y = int(822 * scale_y)

                click_fn = getattr(coordinator, "click", lambda x, y: self.orchestrator._click(x, y))
                press_fn = getattr(coordinator, "press_key", None)

                WaystoneLoaderGuard.recover_cursor_item_to_inventory(
                    click_func=click_fn,
                    slot_x=safe_slot_x,
                    slot_y=safe_slot_y,
                    press_key_func=press_fn,
                )
                self.log("✅ [CURSOR_STUCK_GUARD] Đã hoàn trả vật phẩm an toàn về túi đồ.")
                return True
        except Exception as e:
            self.log(f"Lưu ý Cursor Stuck Guard: {e}")

        return False

    def execute(
        self,
        coordinator: Optional[Any] = None,
        inspect_items_live: bool = False,
        is_post_map: bool = False,
        dry_run: bool = False,
    ) -> Dict[str, Any]:
        """
        Thực thi toàn diện chu trình Stage 0 tại Hideout.
        Tuân thủ INV-FOCUS-SAFETY-SEPARATION, INV-KEY-NO-F-FOR-INTERACT, INV-STASH-CTRL-CLICK.
        """
        phase = "post_map" if is_post_map else "pre_map"
        res = Stage0Result(phase=phase, target_tier=self.target_waystone_tier)

        self.log(f"--- STAGE 0: Stash Logistics & Restock ({phase.upper()}) ---")

        # 1. Khóa an toàn Focus & Simulation (INV-FOCUS-SAFETY-SEPARATION)
        effective_simulated = (
            self.is_simulated
            or dry_run
            or (coordinator is not None and getattr(coordinator, "is_simulated", False))
        )
        if effective_simulated:
            self.orchestrator.is_simulated = True
            set_input_simulation_mode(True)
        else:
            if coordinator and hasattr(coordinator, "ensure_focus"):
                coordinator.ensure_focus()
            else:
                self.orchestrator._ensure_focus()

        try:
            # 2. Kiểm tra vị trí an toàn tại Hideout (INV-ATLAS-01)
            if (
                not effective_simulated
                and coordinator
                and hasattr(coordinator, "log_watcher")
                and coordinator.log_watcher
            ):
                seeded = coordinator.log_watcher.seed_latest_playable_zone()
                if seeded and seeded.area_name and "hideout" not in seeded.area_name.lower():
                    res.error = f"Nhân vật đang ở '{seeded.area_name}', không phải Hideout! Từ chối mở Stash."
                    self.log(f"❌ {res.error}")
                    return res.to_dict()

            # 3. Thực thi chu trình Stash qua orchestrator.run_full_stash_cycle
            stash_res = self.orchestrator.run_full_stash_cycle(inspect_items_live=inspect_items_live)

            # 3.5. Khóa an toàn chống dính chuột sau chuỗi Micro-Burst Ctrl+Click (INV-CURSOR-SAFETY)
            self.check_and_recover_stuck_cursor(coordinator=coordinator)

            # Cập nhật kết quả
            res.stash_opened = stash_res.get("stash_opened", False)
            res.tabs_detected = stash_res.get("tabs_detected", 0)
            res.items_deposited = stash_res.get("items_deposited", 0)
            res.waystone_withdrawn = stash_res.get("waystone_withdrawn", False)
            res.stash_closed = stash_res.get("stash_closed", False)
            res.error = stash_res.get("error", "")

            if stash_res.get("success"):
                res.status = "SUCCESS"
                self.log(f"✅ Stash Routine thành công: {res.items_deposited} đồ đã cất, {res.tabs_detected} tabs nhận diện.")
            else:
                res.status = "FAILED"
                self.log(f"⚠️ Stash Routine kết thúc: {res.error}")

            # Đếm số waystone hiện có trong túi
            res.current_waystones_in_bag = self.count_waystones_in_inventory(coordinator=coordinator)
            return res.to_dict()

        finally:
            if effective_simulated:
                set_input_simulation_mode(None)

    def run_cycle(
        self,
        coordinator: Any,
        target_slot_idx: int = 0,
        enable_stashing: bool = True,
        enable_post_stashing: bool = True,
        allow_portal_bypass: bool = True,
        inspect_items_live: bool = False,
    ) -> Dict[str, Any]:
        """
        Ủy nhiệm chu trình cày map khép kín tự hành cho coordinator.
        Tuân thủ Rule 4 (Anti-Monolithic Delegation).
        """
        return coordinator.execute_pipeline(
            target_slot_idx=target_slot_idx,
            enable_stashing=enable_stashing,
            enable_post_stashing=enable_post_stashing,
            allow_portal_bypass=allow_portal_bypass,
        )
