#!/usr/bin/env python3

import os
import sys
import json
import pytest
from unittest.mock import patch, MagicMock, mock_open, call
from pathlib import Path

# Add parent directory to path so we can import check_package_builds
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from check_package_builds import build_package_test, load_package_config, main

class TestCheckPackageBuilds:
    
    def test_load_package_config(self):
        """Test loading package configuration from YAML file."""
        mock_yaml_content = """
        packages:
          test-package:
            github_repo: "owner/repo"
            version_method: "release"
            pkgbuild_path: "test-package/PKGBUILD"
        """
        
        with patch('builtins.open', mock_open(read_data=mock_yaml_content)) as mock_file:
            result = load_package_config()
            
            assert 'test-package' in result
            assert result['test-package']['github_repo'] == 'owner/repo'
    
    def test_package_build_success(self):
        """Test successful package build with paru."""
        with patch('subprocess.run') as mock_run, \
             patch('os.makedirs') as mock_makedirs:
            
            # Configure mocks for successful build
            build_success = MagicMock()
            build_success.returncode = 0
            build_success.stdout = "==> Building package: test-package...\n==> Finished making: test-package"
            build_success.stderr = ""
            
            cleanup_process = MagicMock()
            
            # Set up the mock to return different values on consecutive calls
            mock_run.side_effect = [build_success, cleanup_process]
            
            # Test the package build function
            result = build_package_test('test-package')
            
            # Verify the result
            assert result['success'] == True
            assert 'Build successful' in result['log']
            
            # Verify paru -S was called with correct flags
            first_call_args = mock_run.call_args_list[0][0][0]
            assert 'paru' == first_call_args[0]
            assert '-S' == first_call_args[1]
            assert '--asexplicit' in first_call_args
    
    def test_package_build_fallback(self):
        """Test fallback with additional flags when regular build fails."""
        with patch('subprocess.run') as mock_run, \
             patch('os.makedirs') as mock_makedirs:
            
            # Configure mocks for failed build, successful fallback
            build_fail = MagicMock()
            build_fail.returncode = 1
            build_fail.stdout = ""
            build_fail.stderr = "==> ERROR: One or more PGP signatures could not be verified!"
            
            fallback_success = MagicMock()
            fallback_success.returncode = 0
            fallback_success.stdout = "==> Building package: test-package...\n==> Finished making: test-package"
            fallback_success.stderr = ""
            
            cleanup_process = MagicMock()
            
            # Configure mock to return different results on consecutive calls
            mock_run.side_effect = [
                build_fail,         # First build fails
                fallback_success,   # Fallback build succeeds  
                cleanup_process     # Cleanup
            ]
            
            # Test the package build function
            result = build_package_test('test-package')
            
            # Verify the result
            assert result['success'] == True
            assert 'First build attempt failed' in result['log']
            
            # Verify all calls were made
            assert mock_run.call_count >= 2
            
            # Check first call (regular build)
            args1 = mock_run.call_args_list[0][0][0]
            assert 'paru' in args1
            assert '-S' in args1
            
            # Check second call (fallback build with additional flags)
            args2 = mock_run.call_args_list[1][0][0]
            assert 'paru' in args2
            assert '--mflags=--skippgpcheck' in args2
            assert '--overwrite=*' in args2
    
    def test_package_build_failure(self):
        """Test package build failure detection."""
        with patch('subprocess.run') as mock_run, \
             patch('os.makedirs') as mock_makedirs:
            
            # Configure mocks for failed builds
            build_fail = MagicMock()
            build_fail.returncode = 1
            build_fail.stdout = ""
            build_fail.stderr = "error: target not found: some-dependency"
            
            fallback_fail = MagicMock()
            fallback_fail.returncode = 1
            fallback_fail.stdout = ""
            fallback_fail.stderr = "error: target not found: some-dependency"
            
            cleanup_process = MagicMock()
            
            # Configure mocks for consecutive calls
            mock_run.side_effect = [
                build_fail,         # First build fails
                fallback_fail,      # Fallback build also fails
                cleanup_process     # Cleanup
            ]
            
            # Test the package build function
            result = build_package_test('test-package')
            
            # Verify the result
            assert result['success'] == False
            assert result['error'] == "Dependency not found"
    
    def test_main_function(self):
        """Test main function that processes multiple packages."""
        mock_packages = ['package1', 'package2']
        
        with patch('sys.argv', ['check_package_builds.py'] + mock_packages), \
             patch('check_package_builds.build_package_test') as mock_test_build, \
             patch('check_package_builds.write_results') as mock_write, \
             patch('check_package_builds.load_package_config') as mock_load_config, \
             patch('sys.exit') as mock_exit:  # Mock sys.exit to prevent test from exiting
            
            # Configure test_package_build to return success for package1 and failure for package2
            mock_results = [
                {'package': 'package1', 'success': True, 'error': "", 'log': "Build succeeded"},
                {'package': 'package2', 'success': False, 'error': "Dependency not found", 'log': "Build failed"}
            ]
            mock_test_build.side_effect = mock_results
            
            # Mock package config
            mock_load_config.return_value = {
                'package1': {'github_repo': 'owner/repo1'},
                'package2': {'github_repo': 'owner/repo2'}
            }
            
            # Run main
            main()
            
            # Verify test_package_build was called for both packages
            mock_test_build.assert_has_calls([
                call('package1'),
                call('package2')
            ])
            
            # Verify write_results was called with both results
            mock_write.assert_called_once()
            args, _ = mock_write.call_args
            assert len(args[0]) == 2  # Two results
            assert args[0][0]['package'] == 'package1'
            assert args[0][1]['package'] == 'package2'
            
            # Verify sys.exit was called with code 0 even though a package failed
            mock_exit.assert_called_with(0) 