#!/usr/bin/env python3
"""
DailyNotification Plugin Automated Test Suite
Usage: python3 daily-notification-test.py [OPTIONS]
"""

import subprocess
import time
import json
import sys
import argparse
from typing import Optional, Dict, Any, List
from dataclasses import dataclass
from enum import Enum

class TestResult(Enum):
    PASS = "PASS"
    FAIL = "FAIL"
    SKIP = "SKIP"

@dataclass
class TestCase:
    name: str
    description: str
    result: TestResult
    duration: float
    error: Optional[str] = None

class DailyNotificationTester:
    def __init__(self, package: str = "org.timesafari.dailynotification", verbose: bool = False):
        self.package = package
        self.activity = f"{package}/.MainActivity"
        self.verbose = verbose
        self.test_results: List[TestCase] = []
        
    def log(self, message: str, level: str = "INFO"):
        """Log message with timestamp"""
        timestamp = time.strftime("%H:%M:%S")
        if level == "ERROR":
            print(f"❌ [{timestamp}] {message}")
        elif level == "SUCCESS":
            print(f"✅ [{timestamp}] {message}")
        elif level == "WARNING":
            print(f"⚠️  [{timestamp}] {message}")
        elif level == "INFO":
            print(f"ℹ️  [{timestamp}] {message}")
        else:
            print(f"[{timestamp}] {message}")
    
    def run_adb_command(self, command: str, capture_output: bool = True) -> subprocess.CompletedProcess:
        """Run ADB command and return result"""
        full_command = f"adb {command}"
        if self.verbose:
            self.log(f"Running: {full_command}")
        
        try:
            return subprocess.run(
                full_command, 
                shell=True, 
                capture_output=capture_output, 
                text=True,
                timeout=30
            )
        except subprocess.TimeoutExpired:
            self.log(f"Command timed out: {full_command}", "ERROR")
            raise
    
    def is_app_running(self) -> bool:
        """Check if app is currently running"""
        result = self.run_adb_command(f'shell "ps | grep {self.package}"')
        return result.returncode == 0 and self.package in result.stdout
    
    def launch_app(self) -> bool:
        """Launch the app"""
        self.log("Launching app...")
        result = self.run_adb_command(f"shell am start -n {self.activity}")
        time.sleep(3)  # Wait for app to load
        return self.is_app_running()
    
    def send_to_background(self) -> bool:
        """Send app to background"""
        self.log("Sending app to background...")
        self.run_adb_command("shell input keyevent KEYCODE_HOME")
        time.sleep(2)
        return self.is_app_running()
    
    def force_stop_app(self) -> bool:
        """Force stop the app"""
        self.log("Force stopping app...")
        self.run_adb_command(f"shell am force-stop {self.package}")
        time.sleep(2)
        return not self.is_app_running()
    
    def check_notification_logs(self, timeout: int = 60) -> bool:
        """Check for notification success in logs"""
        self.log(f"Checking notification logs (timeout: {timeout}s)...")
        start_time = time.time()
        
        while time.time() - start_time < timeout:
            result = self.run_adb_command("logcat -d")
            if "Notification displayed successfully" in result.stdout:
                return True
            time.sleep(5)
        return False
    
    def check_permissions(self) -> Dict[str, bool]:
        """Check app permissions"""
        self.log("Checking app permissions...")
        result = self.run_adb_command(f"shell dumpsys package {self.package}")
        
        permissions = {
            "notifications": "POST_NOTIFICATIONS" in result.stdout,
            "exact_alarm": "SCHEDULE_EXACT_ALARM" in result.stdout,
            "wake_lock": "WAKE_LOCK" in result.stdout
        }
        
        return permissions
    
    def check_scheduled_alarms(self) -> bool:
        """Check if any alarms are scheduled for the app"""
        self.log("Checking scheduled alarms...")
        result = self.run_adb_command("shell \"dumpsys alarm | grep timesafari\"")
        return result.returncode == 0 and self.package in result.stdout
    
    def run_test(self, test_name: str, test_func, *args, **kwargs) -> TestCase:
        """Run a single test case"""
        self.log(f"Running test: {test_name}")
        start_time = time.time()
        
        try:
            result = test_func(*args, **kwargs)
            duration = time.time() - start_time
            
            if result:
                self.log(f"Test passed: {test_name}", "SUCCESS")
                return TestCase(test_name, "", TestResult.PASS, duration)
            else:
                self.log(f"Test failed: {test_name}", "ERROR")
                return TestCase(test_name, "", TestResult.FAIL, duration, "Test returned False")
                
        except Exception as e:
            duration = time.time() - start_time
            self.log(f"Test error: {test_name} - {str(e)}", "ERROR")
            return TestCase(test_name, "", TestResult.FAIL, duration, str(e))
    
    def run_test_suite(self) -> Dict[str, Any]:
        """Run complete test suite"""
        self.log("🧪 Starting DailyNotification Test Suite")
        self.log("=" * 50)
        
        # Check ADB connection
        result = self.run_adb_command("devices")
        if "device" not in result.stdout:
            self.log("No Android device connected via ADB", "ERROR")
            sys.exit(1)
        
        self.log("ADB device connected", "SUCCESS")
        
        # Test 1: App Launch
        test_case = self.run_test("App Launch", self.launch_app)
        self.test_results.append(test_case)
        
        # Test 2: Background Test
        test_case = self.run_test("Background Operation", self.send_to_background)
        self.test_results.append(test_case)
        
        # Test 3: Force Stop Test
        test_case = self.run_test("Force Stop", self.force_stop_app)
        self.test_results.append(test_case)
        
        # Test 4: Permission Check
        def check_permissions_test():
            permissions = self.check_permissions()
            return any(permissions.values())
        
        test_case = self.run_test("Permission Check", check_permissions_test)
        self.test_results.append(test_case)
        
        # Test 5: Alarm Check
        test_case = self.run_test("Alarm Scheduling", self.check_scheduled_alarms)
        self.test_results.append(test_case)
        
        # Test 6: Notification Test (requires manual scheduling)
        self.log("📱 Manual Notification Test")
        self.log("⚠️  Manual step required: Schedule notification in app", "WARNING")
        input("Press Enter when notification is scheduled...")
        
        test_case = self.run_test("Notification Delivery", self.check_notification_logs, 120)
        self.test_results.append(test_case)
        
        return self.generate_report()
    
    def generate_report(self) -> Dict[str, Any]:
        """Generate test report"""
        total_tests = len(self.test_results)
        passed_tests = sum(1 for test in self.test_results if test.result == TestResult.PASS)
        failed_tests = sum(1 for test in self.test_results if test.result == TestResult.FAIL)
        
        report = {
            "summary": {
                "total": total_tests,
                "passed": passed_tests,
                "failed": failed_tests,
                "success_rate": (passed_tests / total_tests * 100) if total_tests > 0 else 0
            },
            "tests": [
                {
                    "name": test.name,
                    "result": test.result.value,
                    "duration": test.duration,
                    "error": test.error
                }
                for test in self.test_results
            ]
        }
        
        return report
    
    def print_report(self, report: Dict[str, Any]):
        """Print test report"""
        self.log("\n📊 Test Results Summary:")
        self.log("=" * 30)
        
        summary = report["summary"]
        self.log(f"Total Tests: {summary['total']}")
        self.log(f"Passed: {summary['passed']}")
        self.log(f"Failed: {summary['failed']}")
        self.log(f"Success Rate: {summary['success_rate']:.1f}%")
        
        self.log("\nDetailed Results:")
        for test in report["tests"]:
            status = "✅ PASS" if test["result"] == "PASS" else "❌ FAIL"
            duration = f"({test['duration']:.1f}s)"
            self.log(f"{test['name']}: {status} {duration}")
            if test["error"]:
                self.log(f"  Error: {test['error']}", "ERROR")

def main():
    parser = argparse.ArgumentParser(description="DailyNotification Plugin Test Suite")
    parser.add_argument("-v", "--verbose", action="store_true", help="Enable verbose output")
    parser.add_argument("-p", "--package", default="org.timesafari.dailynotification", help="App package name")
    parser.add_argument("-o", "--output", help="Output report to JSON file")
    parser.add_argument("--timeout", type=int, default=120, help="Test timeout in seconds")
    
    args = parser.parse_args()
    
    tester = DailyNotificationTester(package=args.package, verbose=args.verbose)
    report = tester.run_test_suite()
    tester.print_report(report)
    
    # Save report to file if specified
    if args.output:
        with open(args.output, 'w') as f:
            json.dump(report, f, indent=2)
        tester.log(f"Report saved to: {args.output}")
    
    # Exit with error code if any test failed
    if report["summary"]["failed"] > 0:
        sys.exit(1)

if __name__ == "__main__":
    main()
