"""
Headless GUI module for testing without tkinter display.
Provides mock classes for GUI testing in environments without X server.
"""

from typing import List, Dict, Any, Optional
from pathlib import Path
import json
import datetime
import os
from ..model import ScanRequest, ScanResult
from ..scanner import SentinelScanner
from ..reporting import HistoryStore, ReportEngine
from ..subscription import SubscriptionManager, SubscriptionTier
from ..subscription.validator import LicenseError, LicenseValidator
from .i18n import localization


class MockVar:
    """Mock variable for tkinter variables."""
    def __init__(self, value=None):
        self._value = value
    
    def get(self):
        return self._value
    
    def set(self, value):
        self._value = value


class HeadlessWebSentinelGUI:
    """
    Headless version of WebSentinelGUI for testing without tkinter.
    Provides the same interface but without actual GUI components.
    """
    
    def __init__(self, subscription_tier: str | SubscriptionTier | None = None):
        # Initialize variables without tkinter
        self.domains_var = MockVar("")
        self.allow_invasive_var = MockVar(False)
        self.timeout_var = MockVar(5.0)
        self.current_scan_thread = None
        self.scan_results: List[ScanResult] = []
        self.is_scanning = False
        
        # Module variables
        self.module_vars = {
            'tls': MockVar(True),
            'headers': MockVar(True),
            'static-analysis': MockVar(True),
            'injection': MockVar(True),
            'third-party': MockVar(False)
        }
        
        # Configuration
        self.config_file = Path.home() / ".web-sentinel" / "gui-config.json"
        self.config = {}
        self.load_config()
        
        # Scanner and storage
        self.scanner = SentinelScanner()
        history_path = self.config_file.parent / "history.json"
        self.history_store = HistoryStore(history_path)
        self.report_engine = ReportEngine()

        tier = subscription_tier or os.getenv("WS_SUBSCRIPTION_TIER")
        self.subscription_manager = SubscriptionManager(user_id="headless")
        if tier:
            self.subscription_manager.set_tier(tier)
        self.license_validator = LicenseValidator(self.subscription_manager)
        
        self._print("messages.headless.init")

    def _text(self, key: str, **kwargs) -> str:
        return localization.t(key).format(**kwargs)

    def _print(self, key: str, **kwargs) -> None:
        print(self._text(key, **kwargs))
    
    def load_config(self):
        """Load configuration from file."""
        try:
            if self.config_file.exists():
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    self.config = json.load(f)
        except Exception:
            self.config = {}
    
    def save_config(self):
        """Save configuration to file."""
        try:
            self.config_file.parent.mkdir(parents=True, exist_ok=True)
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(self.config, f, indent=2)
        except Exception:
            pass
    
    def get_domains(self) -> List[str]:
        """Get list of domains from input."""
        domains_text = self.domains_var.get() or ""
        return [d.strip() for d in domains_text.split('\n') if d.strip()]
    
    def set_domains(self, domains: List[str]):
        """Set domains list."""
        self.domains_var.set('\n'.join(domains))
    
    def get_selected_modules(self) -> List[str]:
        """Get list of selected modules."""
        return [name for name, var in self.module_vars.items() if var.get()]
    
    def set_selected_modules(self, modules: List[str]):
        """Set selected modules."""
        for name, var in self.module_vars.items():
            var.set(name in modules)
    
    def start_scan(self) -> bool:
        """
        Start scan in headless mode.
        Returns True if scan started successfully, False otherwise.
        """
        domains = self.get_domains()
        if not domains:
            self._print("messages.headless.no_domains")
            return False

        domain_limit = self.subscription_manager.get_domain_limit()
        if domain_limit != -1 and len(domains) > domain_limit:
            self._print("messages.headless.domain_limit", limit=domain_limit)
            return False
            
        selected_modules = self.get_selected_modules()
        if not selected_modules:
            self._print("messages.headless.no_modules")
            return False

        if self.allow_invasive_var.get():
            if not self.can_start_invasive_scan():
                self.allow_invasive_var.set(False)
                self._print("messages.headless.invasive_not_allowed")
                return False

        self._print("messages.headless.scan_start", count=len(domains))
        self._print("messages.headless.domains_list", domains=", ".join(domains))
        self._print("messages.headless.modules_list", modules=", ".join(selected_modules))
        
        self.is_scanning = True
        self.scan_results.clear()
        
        try:
            # Perform scan for each domain
            for domain in domains:
                request = ScanRequest(
                    domain=domain,
                    timeout=self.timeout_var.get(),
                    allow_invasive=self.allow_invasive_var.get()
                )
                
                self._print("messages.headless.scanning_domain", domain=domain)
                result = self.scanner.run(request, selected_modules)
                self.scan_results.append(result)

                self._print("messages.headless.domain_findings", count=len(result.findings))

            self._print("messages.headless.scan_complete", count=len(self.scan_results))
            self.display_results()
            return True
            
        except Exception as e:
            self._print("messages.headless.scan_error", error=e)
            return False
        finally:
            self.is_scanning = False
    
    def display_results(self):
        """Display scan results in headless mode."""
        if not self.scan_results:
            self._print("messages.headless.no_results")
            return
        
        print("\n" + "="*60)
        self._print("messages.headless.results_header")
        print("="*60)
        
        total_findings = sum(len(result.findings) for result in self.scan_results)
        self._print("messages.headless.results_summary", domains=len(self.scan_results), findings=total_findings)
        
        for result in self.scan_results:
            self._print("messages.headless.domain_header", domain=result.request.domain)
            
            if not result.findings:
                self._print("messages.headless.domain_no_findings")
                continue
            
            # Group by severity
            by_severity: Dict[str, List[Finding]] = {}
            for finding in result.findings:
                severity = finding.severity
                by_severity.setdefault(severity, []).append(finding)
            
            for severity in ['critical', 'high', 'medium', 'low', 'info']:
                severity_findings = by_severity.get(severity)
                if not severity_findings:
                    continue
                self._print("messages.headless.severity_block", severity=severity.upper(), count=len(severity_findings))
                for finding in severity_findings[:3]:  # Show first 3
                    print(f"      • {finding.title}")
                if len(severity_findings) > 3:
                    self._print("messages.headless.more_findings", count=len(severity_findings) - 3)
    
    def export_report(self, format_type: str = "json", output_path: Optional[str] = None) -> Optional[str]:
        """
        Export scan results to file.
        Returns path of exported file or None if failed.
        """
        if not self.scan_results:
            self._print("messages.headless.no_results_export")
            return None
        
        try:
            if format_type.lower() == "json":
                if not output_path:
                    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
                    output_path = f"web_sentinel_report_{timestamp}.json"
                
                data = {
                    "timestamp": datetime.datetime.now().isoformat(),
                    "domains": [result.request.domain for result in self.scan_results],
                    "results": [
                        {
                            "domain": result.request.domain,
                            "findings": [finding.to_dict() for finding in result.findings]
                        }
                        for result in self.scan_results
                    ]
                }
                
                with open(output_path, 'w', encoding='utf-8') as f:
                    json.dump(data, f, indent=2, ensure_ascii=False)
                
                self._print("messages.headless.export_json", path=output_path)
                return output_path
            
            elif format_type.lower() == "html":
                if not self.subscription_manager.can_export_html():
                    self._print("messages.headless.html_export_not_allowed")
                    return None
                if not output_path:
                    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
                    output_path = f"web_sentinel_report_{timestamp}.html"
                
                # Use report engine for HTML generation
                context = self.report_engine.build_context(self.scan_results[0])
                html_content = self.report_engine.render_html(context)
                with open(output_path, 'w', encoding='utf-8') as f:
                    f.write(html_content)
                
                self._print("messages.headless.export_html", path=output_path)
                return output_path
            
            else:
                self._print("messages.headless.unsupported_format", format=format_type)
                return None
                
        except Exception as e:
            self._print("messages.headless.export_failed", error=e)
            return None
    
    def run_headless_test(self, test_domains: List[str], test_modules: List[str] = None) -> Dict[str, Any]:
        """
        Run a complete test in headless mode.
        Returns test results summary.
        """
        self._print("messages.headless.test_start")
        
        # Set up test parameters
        self.set_domains(test_domains)
        if test_modules:
            self.set_selected_modules(test_modules)
        else:
            # Use default safe modules
            self.set_selected_modules(['tls', 'headers'])
        
        # Run scan
        scan_success = self.start_scan()
        
        # Generate summary
        result = {
            "test_timestamp": datetime.datetime.now().isoformat(),
            "domains_tested": test_domains,
            "modules_used": self.get_selected_modules(),
            "scan_success": scan_success,
            "total_findings": sum(len(result.findings) for result in self.scan_results) if scan_success else 0,
            "results_summary": {}
        }
        
        if scan_success and self.scan_results:
            for scan_result in self.scan_results:
                domain = scan_result.request.domain
                result["results_summary"][domain] = {
                    "findings_count": len(scan_result.findings),
                    "severities": {}
                }
                
                # Count by severity
                for finding in scan_result.findings:
                    severity = finding.severity
                    if severity not in result["results_summary"][domain]["severities"]:
                        result["results_summary"][domain]["severities"][severity] = 0
                    result["results_summary"][domain]["severities"][severity] += 1
        
        self._print("messages.headless.test_complete", result=result)
        return result

    def can_start_invasive_scan(self) -> bool:
        try:
            self.license_validator.ensure_invasive_tests_allowed()
        except LicenseError:
            return False
        return True

    def set_subscription_tier(self, tier: str | SubscriptionTier) -> None:
        self.subscription_manager.set_tier(tier)


def get_gui_class(headless: bool = False):
    """
    Factory function to get appropriate GUI class.
    
    Args:
        headless: If True, return headless version. If False, try tkinter version.
    
    Returns:
        GUI class (either WebSentinelGUI or HeadlessWebSentinelGUI)
    """
    if headless:
        return HeadlessWebSentinelGUI
    
    try:
        from .main_window import WebSentinelGUI
        try:
            import tkinter as tk

            test_root = tk.Tk()
            test_root.destroy()
        except Exception as exc:
            print(localization.t("messages.headless.tk_init_failed").format(error=exc))
            print(localization.t("messages.headless.fallback_headless"))
            return HeadlessWebSentinelGUI
        return WebSentinelGUI
    except ImportError as e:
        print(localization.t("messages.headless.tk_not_available").format(error=e))
        print(localization.t("messages.headless.fallback_headless"))
        return HeadlessWebSentinelGUI
