import unittest
from unittest.mock import patch, MagicMock
import io
import json
import sys
import os

# Add project root to sys.path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src")))

# Import after path fix
from scripts.cli_tool_bridge import main

class TestCliToolBridge(unittest.TestCase):
 def setUp(self) -> None:
  os.environ['GEMINI_CLI_HOOK_CONTEXT'] = 'manual_slop'
  self.tool_call = {
   'tool_name': 'read_file',
   'tool_input': {'path': 'test.txt'}
  }

 @patch('sys.stdin', new_callable=io.StringIO)
 @patch('sys.stdout', new_callable=io.StringIO)
 @patch('api_hook_client.ApiHookClient.request_confirmation')
 def test_allow_decision(self, mock_request: MagicMock, mock_stdout: MagicMock, mock_stdin: MagicMock) -> None:
  mock_stdin.write(json.dumps(self.tool_call))
  mock_stdin.seek(0)
  # 2. Mock ApiHookClient to return approved
  mock_request.return_value = {'approved': True}
  # Run main
  main()
  # 3. Capture stdout and assert allow
  output = json.loads(mock_stdout.getvalue().strip())
  self.assertEqual(output.get('decision'), 'allow')

 @patch('sys.stdin', new_callable=io.StringIO)
 @patch('sys.stdout', new_callable=io.StringIO)
 @patch('api_hook_client.ApiHookClient.request_confirmation')
 def test_deny_decision(self, mock_request: MagicMock, mock_stdout: MagicMock, mock_stdin: MagicMock) -> None:
  mock_stdin.write(json.dumps(self.tool_call))
  mock_stdin.seek(0)
  # 4. Mock ApiHookClient to return denied
  mock_request.return_value = {'approved': False}
  main()
  # Assert deny
  output = json.loads(mock_stdout.getvalue().strip())
  self.assertEqual(output.get('decision'), 'deny')

 @patch('sys.stdin', new_callable=io.StringIO)
 @patch('sys.stdout', new_callable=io.StringIO)
 @patch('api_hook_client.ApiHookClient.request_confirmation')
 def test_unreachable_hook_server(self, mock_request: MagicMock, mock_stdout: MagicMock, mock_stdin: MagicMock) -> None:
  mock_stdin.write(json.dumps(self.tool_call))
  mock_stdin.seek(0)
  # 5. Test case where hook server is unreachable (exception)
  mock_request.side_effect = Exception("Connection refused")
  main()
  # Assert deny on error
  output = json.loads(mock_stdout.getvalue().strip())
  self.assertEqual(output.get('decision'), 'deny')

if __name__ == '__main__':
 unittest.main()
