import os
import shutil
from sys import platform
import tempfile
import unittest
import pytest
from unittest.mock import MagicMock, call, patch
from pathlib import Path
from datetime import datetime, timezone

from safety.tool.interceptors.windows import WindowsInterceptor


@pytest.mark.windows_only
@pytest.mark.skipif(platform not in ["win32"], 
                    reason="Windows-specific tests")
class TestWindowsInterceptor(unittest.TestCase):
    
    def setUp(self):        
        self.temp_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, self.temp_dir)

    @patch('safety.tool.interceptors.windows.Path.home')
    @patch('safety.tool.interceptors.base.datetime')
    @patch('safety.tool.interceptors.base.get_version')
    @patch('safety.tool.interceptors.windows.winreg')
    def test_interceptors_all_tools(self, mock_winreg, mock_version, 
                                  mock_datetime, mock_home):
        import winreg

        mock_home.return_value = Path(self.temp_dir)
        mock_version.return_value = "1.0.0"
        mock_now = datetime(2024, 1, 1, tzinfo=timezone.utc)
        mock_datetime.now.return_value = mock_now

        # Mock Windows registry
        mock_key = MagicMock()
        mock_winreg.OpenKey.return_value.__enter__.return_value = mock_key

        original_path = "C:\\existing\\path"
        mock_winreg.QueryValueEx.return_value = (original_path, mock_winreg.REG_EXPAND_SZ)
            
        mock_winreg.HKEY_CURRENT_USER = winreg.HKEY_CURRENT_USER
        mock_winreg.KEY_ALL_ACCESS = winreg.KEY_ALL_ACCESS
        mock_winreg.REG_EXPAND_SZ = winreg.REG_EXPAND_SZ

        # Initialize interceptor
        interceptor = WindowsInterceptor()

        expected_new_path = f"{str(interceptor.scripts_dir)}{os.pathsep}{original_path}"
        
        # Test installation
        result = interceptor.install_interceptors()
        self.assertTrue(result)
        
        # Verify bat files were created
        for tool in interceptor.tools.values():
            for binary in tool.binary_names:
              bat_path = interceptor.scripts_dir / f'{binary}.bat'
              self.assertTrue(bat_path.exists(), 
                              f"Bat file for {binary} does not exist")
              
              expected_bat_content = (
                  "@echo off\n"
                  "REM >>> Safety >>>\n"
                  "REM DO NOT EDIT THIS FILE DIRECTLY\n"
                  f"REM Last updated at: {mock_now.isoformat()}\n"
                  "REM Updated by: safety v1.0.0\n"
                  f"safety {tool.name} %*\n"
                  "REM <<< Safety <<<\n"
              )
              self.assertEqual(bat_path.read_text(), expected_bat_content)
        
        # Verify backup was created
        backup_path = interceptor.backup_dir / 'path_backup.txt'
        self.assertTrue(backup_path.exists())
        expected_backup_content = (
            ">>> Safety >>>\n"
            " DO NOT EDIT THIS FILE DIRECTLY\n"
            f" Last updated at: {mock_now.isoformat()}\n"
            " Updated by: safety v1.0.0\n"
            f"{original_path}\n"
            "<<< Safety <<<\n"
        )
        self.assertEqual(backup_path.read_text(), expected_backup_content)

        mock_winreg.SetValueEx.assert_called_once_with(
            mock_key, 'PATH', 0, winreg.REG_EXPAND_SZ,
            expected_new_path
        )
        
        mock_winreg.SetValueEx.reset_mock()

        # Test remove
        mock_winreg.QueryValueEx.return_value = (expected_new_path, mock_winreg.REG_EXPAND_SZ)

        result = interceptor.remove_interceptors()
        self.assertTrue(result)
        self.assertFalse(interceptor.scripts_dir.exists())

        mock_winreg.SetValueEx.assert_called_once_with(
            mock_key, 'PATH', 0, winreg.REG_EXPAND_SZ, original_path
        )
