"""
NAS Sharing Worker - Thread-based queue processor

REFACTORED: Dùng nas_sharing_auth + nas_sharing_api modules
"""

import os
import time
import threading
import queue
import uuid
from typing import Dict, Optional
from functools import wraps
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchWindowException, WebDriverException
from webdriver_manager.chrome import ChromeDriverManager

from .nas_sharing_api import (
    SharingSessionManager,
    perform_login,
    extract_sharing_id,
    get_initial_path,
    get_file_list,
)


def handle_window_closed(func):
    """Decorator to handle browser crash/close errors"""
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        try:
            return func(self, *args, **kwargs)
        except Exception as e:
            error_msg = str(e).lower()
            is_driver_error = (
                'window already closed' in error_msg or
                'web view not found' in error_msg or
                'max retries exceeded' in error_msg or
                'connection refused' in error_msg or
                isinstance(e, (NoSuchWindowException, WebDriverException))
            )
            
            if is_driver_error:
                print(f"[SharingWorker] ⚠️  Driver error: {str(e)[:100]}")
                print(f"[SharingWorker] 🔄 Resetting driver...")
                try:
                    if self.driver:
                        self.driver.quit()
                except:
                    pass
                self.driver = None
                return func(self, *args, **kwargs)
            else:
                raise
    return wrapper


class SharingLinkWorker:
    """
    Worker processes sharing link requests from queue
    Single browser instance with session persistence
    """
    
    def __init__(self):
        self.driver: Optional[webdriver.Chrome] = None
        self.session_manager: Optional[SharingSessionManager] = None
        self.request_queue = queue.Queue()
        self.results = {}
        self.is_running = False
        self.worker_thread = None
        
        # Thread safety: Lock to prevent concurrent driver access
        self.driver_lock = threading.RLock()
        
        # OTP handling with modal shown tracking
        self.otp_pending = False
        self.otp_code: Optional[str] = None
        self.otp_modal_shown = False
        self.otp_submitted = False  # Track OTP submission success
        
    def start(self):
        """Start worker thread"""
        if self.is_running:
            return
        self.is_running = True
        self.worker_thread = threading.Thread(target=self._worker_loop, daemon=True)
        self.worker_thread.start()
        print("[SharingWorker] Started")
    
    def stop(self):
        """Stop worker and cleanup"""
        self.is_running = False
        if self.driver:
            try:
                # Close all windows first
                if len(self.driver.window_handles) > 0:
                    self.driver.quit()
                else:
                    # Force kill if no windows
                    self.driver.service.process.terminate()
            except Exception as e:
                print(f"[SharingWorker] Warning during cleanup: {e}")
            finally:
                self.driver = None
        print("[SharingWorker] Stopped")
    
    def submit_request(self, url: str) -> str:
        """Submit sharing link for processing"""
        request_id = str(uuid.uuid4())
        self.request_queue.put({
            'id': request_id,
            'url': url,
            'timestamp': time.time()
        })
        
        self.results[request_id] = {
            'status': 'pending',
            'message': 'Đang xử lý sharing link...'
        }
        
        return request_id
    
    def get_result(self, request_id: str) -> Optional[Dict]:
        """Get processing result"""
        return self.results.get(request_id)
    
    def _worker_loop(self):
        """Main worker loop"""
        print("[SharingWorker] Worker loop started")
        
        while self.is_running:
            try:
                try:
                    request = self.request_queue.get(timeout=1)
                except queue.Empty:
                    continue
                
                request_id = request['id']
                url = request['url']
                
                print(f"[SharingWorker] Processing: {url}")
                result = self._process_sharing_link(url)
                
                self.results[request_id] = result
                print(f"[SharingWorker] Completed: {result['status']}")
                
            except Exception as e:
                print(f"[SharingWorker] Error: {e}")
                import traceback
                traceback.print_exc()
    
    def _ensure_driver_ready(self):
        """Setup Chrome driver if not exists - Thread-safe"""
        with self.driver_lock:
            if self.driver:
                try:
                    _ = self.driver.current_url
                    print("[SharingWorker] ✅ Reusing existing driver")
                    return
                except:
                    print("[SharingWorker] ⚠️  Driver dead, creating new...")
                    try:
                        self.driver.quit()
                    except:
                        pass
                    self.driver = None
            
            # ========== TẤT CẢ CODE TẠO DRIVER TRONG LOCK ĐỂ TRÁNH RACE CONDITION ==========
            print("[SharingWorker] 🚀 Creating new Chrome driver...")
            chrome_options = Options()
            
            # Chrome profile from environment
            profile_path_env = os.getenv("NAS_CHROME_PROFILE_PATH")
            if not profile_path_env:
                raise ValueError("NAS_CHROME_PROFILE_PATH must be set in .env.local")
            
            # Resolve absolute path
            current_file = os.path.abspath(__file__)
            backend_dir = os.path.dirname(os.path.dirname(current_file))
            workspace_root = os.path.dirname(backend_dir)
            profile_path = os.path.join(workspace_root, profile_path_env)
            os.makedirs(profile_path, exist_ok=True)
            
            # Chrome options (fix crash issues)
            chrome_options.add_argument(f'user-data-dir={profile_path}')
            chrome_options.add_argument('--disable-gpu')
            chrome_options.add_argument('--start-maximized')
            chrome_options.add_argument('--ignore-certificate-errors')
            
            # Additional stability options (prevent crashes)
            chrome_options.add_argument('--no-sandbox')
            chrome_options.add_argument('--disable-dev-shm-usage')
            chrome_options.add_argument('--disable-blink-features=AutomationControlled')
            chrome_options.add_argument('--remote-debugging-port=0')  # Let Chrome choose port
            
            # Disable extensions to avoid conflicts
            chrome_options.add_argument('--disable-extensions')
            
            # Prevent "Chrome is being controlled by automated test software" banner
            chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
            chrome_options.add_experimental_option('useAutomationExtension', False)
            
            service = Service(ChromeDriverManager().install())
            
            try:
                self.driver = webdriver.Chrome(service=service, options=chrome_options)
            except Exception as e:
                print(f"[SharingWorker] ❌ Failed to create Chrome driver: {e}")
                print(f"[SharingWorker] Profile path: {profile_path}")
                print(f"[SharingWorker] Chrome options: {chrome_options.arguments}")
                
                # Try to kill any zombie Chrome processes
                import subprocess
                try:
                    subprocess.run(['taskkill', '/F', '/IM', 'chrome.exe'], 
                                 capture_output=True, timeout=5)
                    subprocess.run(['taskkill', '/F', '/IM', 'chromedriver.exe'], 
                                 capture_output=True, timeout=5)
                    print(f"[SharingWorker] Killed zombie Chrome processes, retrying...")
                    time.sleep(2)
                    
                    # Retry once after killing zombies
                    self.driver = webdriver.Chrome(service=service, options=chrome_options)
                except Exception as retry_error:
                    print(f"[SharingWorker] ❌ Retry also failed: {retry_error}")
                    raise RuntimeError(
                        f"Cannot create Chrome driver. "
                        f"Try: 1) Close all Chrome windows, 2) Delete chrome_profile_nas folder, 3) Restart"
                    ) from e
            
            # Create session manager
            self.session_manager = SharingSessionManager(self.driver)
            
            print(f"[SharingWorker] ✅ Driver created, profile: {profile_path}")
    
    @handle_window_closed
    def _perform_login(self) -> bool:
        """
        Perform DSM login using nas_sharing_auth module
        OTP via modal pattern
        """
        if not self.driver or not self.session_manager:
            raise RuntimeError("Driver not initialized")
        
        # Type safety assertions
        assert self.driver is not None
        assert self.session_manager is not None
        
        # OTP callback for nas_sharing_auth.perform_login()
        def otp_callback() -> Optional[str]:
            """Wait for OTP from frontend modal"""
            # Set pending flag
            if not self.otp_pending:
                self.otp_pending = True
                self.otp_modal_shown = False
                self.otp_submitted = False
            
            # Wait for OTP (max 5 minutes)
            for i in range(300):
                if self.otp_code:
                    code = self.otp_code
                    # DON'T reset flags yet - wait for login completion
                    self.otp_code = None
                    return code
                
                time.sleep(1)
                if i % 10 == 0:
                    print(f"[SharingWorker] ⏳ Waiting for OTP... ({300-i}s)")
            
            # Timeout
            self.otp_pending = False
            self.otp_modal_shown = False
            self.otp_submitted = False
            return None
        
        # Call perform_login() from nas_sharing_api
        success = perform_login(
            driver=self.driver,
            otp_callback=otp_callback
        )
        
        if success:
            print("[SharingWorker] ✅ Login successful!")
            
            # QUAN TRỌNG: Mark OTP submitted TRƯỚC KHI reset flags
            if self.otp_pending:
                self.otp_submitted = True
                print("[SharingWorker] ✅ OTP đã được xác nhận thành công")
            
            # Đợi để Chrome profile lưu cookies (quan trọng!)
            print("[SharingWorker] ⏳ Đợi 5s để lưu cookies vào Chrome profile...")
            time.sleep(5)
            
            # Reset OTP flags sau khi đã đợi
            self.otp_pending = False
            self.otp_modal_shown = False
            
            print("[SharingWorker] ✅ Cookies đã được lưu vào Chrome profile")
            return True
        
        # Login failed - reset flags
        self.otp_pending = False
        self.otp_modal_shown = False
        self.otp_submitted = False
        return False
    
    @handle_window_closed
    def _process_sharing_link(self, url: str) -> Dict:
        """
        Process sharing link - navigate và extract file list
        """
        from .nas_sharing_api.selenium_operations import extract_sharing_id, get_initial_path, get_file_list
        
        try:
            sharing_id = extract_sharing_id(url)
            if not sharing_id:
                raise Exception("Cannot extract sharing_id from URL")
            
            print(f"[SharingWorker] Sharing ID: {sharing_id}")
            
            with self.driver_lock:
                self._ensure_driver_ready()
                assert self.driver is not None
                
                # Clear cache để tránh conflict ExtJS
                try:
                    self.driver.execute_cdp_cmd('Network.clearBrowserCache', {})
                except Exception:
                    pass
                
                self.driver.get(url)
                
                try:
                    initial_path = get_initial_path(self.driver)
                except RuntimeError as e:
                    if "NEEDS_LOGIN" in str(e):
                        print("[SharingWorker] Login required")
                        if not self._perform_login():
                            raise Exception("Login failed")
                        
                        # XÓA CACHE sau khi login xong để tránh conflict ExtJS
                        print("[SharingWorker] Xóa cache trước khi truy cập lại sharing link...")
                        try:
                            self.driver.execute_cdp_cmd('Network.clearBrowserCache', {})
                        except Exception as clear_error:
                            print(f"[SharingWorker] ⚠️  Không thể xóa cache: {clear_error}")
                        
                        self.driver.get(url)
                        initial_path = get_initial_path(self.driver)
                    else:
                        raise
                
                print(f"[SharingWorker] 📋 Lấy danh sách ROOT folder: {initial_path}")
                files = get_file_list(self.driver, sharing_id, initial_path)
            
            return {
                'status': 'success',
                'sharing_id': sharing_id,
                'path': initial_path,
                'files': files,
                'total_files': len(files),
                'message': f'Found {len(files)} files'
            }
            
        except Exception as e:
            print(f"[SharingWorker] Error: {e}")
            import traceback
            traceback.print_exc()
            return {
                'status': 'error',
                'message': str(e)
            }
