# Previous content of test_update_packages.py 

import pytest
import json
from unittest.mock import patch, mock_open, MagicMock, call
import os
import sys
from git.repo.fun import is_git_dir
from git import Blob, Repo
from gitdb import IStream
from gitdb.base import OStream
from pyfakefs.fake_filesystem_unittest import Patcher
import yaml

# Add parent directory to path so we can import update_packages
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from update_packages import update_pkgbuild, commit_and_push, main, update_package_checksum

@pytest.fixture
def mock_config():
    return {
        'packages': {
            'test-package': {
                'github_repo': 'owner/repo',
                'version_method': 'release',
                'pkgbuild_path': 'test-package/PKGBUILD'
            },
            'swagger-ui': {
                'github_repo': 'swagger-api/swagger-ui',
                'version_method': 'tag',
                'pkgbuild_path': 'swagger-ui/PKGBUILD',
                'update_checksum': True
            }
        }
    }

@pytest.fixture
def mock_repo():
    repo = MagicMock(spec=Repo)
    repo.index = MagicMock()
    repo.odb = MagicMock()
    
    # Setup index entries
    mock_entry = MagicMock()
    mock_entry.hexsha = 'mock_sha'
    repo.index._entries = {
        'test-package/PKGBUILD': mock_entry,
        'test-package/.SRCINFO': mock_entry
    }
    
    # Setup ODB
    mock_ostream = MagicMock(spec=OStream)
    mock_ostream.stream = b'mock file content'
    mock_ostream.hexsha = 'mock_sha'
    repo.odb.store.return_value = mock_ostream
    
    return repo

@pytest.fixture
def fake_fs():
    with Patcher() as patcher:
        # Setup fake filesystem
        patcher.fs.create_file('.git/config', contents='''[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    worktree = .
''')
        patcher.fs.create_file('.git/HEAD')
        patcher.fs.create_dir('.git/objects')
        patcher.fs.create_dir('.git/refs')
        yield patcher.fs

def test_update_pkgbuild():
    mock_content = """
pkgname=test-package
pkgver=1.2.3
pkgrel=1
    """
    
    with patch('builtins.open', mock_open(read_data=mock_content)) as mock_file, \
         patch('subprocess.run') as mock_run:
        
        result = update_pkgbuild(
            'test-package',
            {'pkgbuild_path': 'test-package/PKGBUILD'},
            '1.2.4'
        )
        
        assert result == True
        mock_file().write.assert_called_once()
        written_content = ''.join(mock_file().write.call_args[0])
        assert 'pkgver=1.2.4' in written_content

def test_update_package_checksum():
    mock_pkgbuild_content = """
pkgname=swagger-ui
pkgver=5.20.0
pkgrel=1
source=("https://github.com/swagger-api/${pkgname}/archive/v${pkgver}.tar.gz")
sha256sums=('1f0c97a19cc8fe3b5b9241fd3e1d2fe43110ff79f7f9f465940c99cbfd06a4b3')
    """
    
    # Create mock package_config with update_checksum set to True
    package_config = {
        'github_repo': 'swagger-api/swagger-ui',
        'update_checksum': True
    }
    
    # Create a mock binary file content for calculating checksum
    mock_tarball_content = b'mock tarball content for testing checksum calculation'
    new_checksum = 'f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b'  # SHA256 of the mock content
    
    with patch('tempfile.TemporaryDirectory') as mock_temp_dir, \
         patch('requests.get') as mock_get, \
         patch('builtins.open', mock_open(read_data=mock_pkgbuild_content)) as mock_file_obj, \
         patch('hashlib.sha256') as mock_sha256:
        
        # Configure the mock response
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.iter_content.return_value = [mock_tarball_content]
        mock_get.return_value = mock_response
        
        # Mock the temporary directory
        mock_temp_dir.return_value.__enter__.return_value = '/tmp/mockdir'
        
        # Mock the sha256 hash calculation to return our precalculated hash
        mock_hash = MagicMock()
        mock_hash.hexdigest.return_value = new_checksum
        mock_sha256.return_value = mock_hash
        
        # Create a more robust file opening mock
        def mock_open_func(*args, **kwargs):
            if args[0].endswith('.tar.gz') and kwargs.get('mode', '') == 'rb':
                # Create a file-like object for binary content
                file_mock = MagicMock()
                file_content = MagicMock()
                
                # Set up read to handle chunk reading
                def read_side_effect(size=None):
                    if hasattr(read_side_effect, 'called'):
                        return b''
                    read_side_effect.called = True
                    return mock_tarball_content
                
                file_content.read = MagicMock(side_effect=read_side_effect)
                file_mock.__enter__ = MagicMock(return_value=file_content)
                file_mock.__exit__ = MagicMock(return_value=False)
                return file_mock
            elif args[0].endswith('.tar.gz') and kwargs.get('mode', '') == 'wb':
                # For writing to the tarball file
                write_mock = MagicMock()
                write_mock.__enter__ = MagicMock(return_value=write_mock)
                write_mock.__exit__ = MagicMock(return_value=None)
                return write_mock
            else:
                # For text files, delegate to the standard mock_open
                return mock_file_obj(*args, **kwargs)
        
        with patch('builtins.open', side_effect=mock_open_func):
            # Call the function to test
            update_package_checksum('swagger-ui/PKGBUILD', package_config, '5.20.1')
        
        # Check that the PKGBUILD was updated with the new checksum
        write_calls = mock_file_obj().write.call_args_list
        written_content = ''.join(call_args[0][0] for call_args in write_calls)
        assert f"sha256sums=('{new_checksum}')" in written_content

def test_commit_and_push(mock_repo, fake_fs):
    from update_packages import commit_and_push
    
    # Setup test files (pyfakefs automatically patches os)
    fake_fs.create_file('test-package/PKGBUILD', contents='pkgver=1.2.3')
    fake_fs.create_file('test-package/.SRCINFO', contents='pkgver = 1.2.3')
    
    # Just call the function normally, no need to pass fs
    commit_and_push(
        package_name='test-package',
        new_version='1.2.4',
        pkgbuild_path='test-package/PKGBUILD',
        repo=mock_repo
    )
    
    # Verify the changes
    mock_repo.index.add.assert_called_with(['test-package/PKGBUILD', 'test-package/.SRCINFO'])
    mock_repo.index.commit.assert_called_with(
        'Update test-package to 1.2.4',
        gpgsign=True
    )
    mock_repo.remote().push.assert_called_once()

def test_main():
    mock_config = {
        'packages': {
            'test-package': {
                'pkgbuild_path': 'test-package/PKGBUILD'
            },
            'swagger-ui': {
                'github_repo': 'swagger-api/swagger-ui',
                'pkgbuild_path': 'swagger-ui/PKGBUILD',
                'update_checksum': True
            }
        }
    }
    
    mock_updates = [
        {
            'name': 'test-package',
            'current': '1.2.3',
            'latest': '1.2.4'
        },
        {
            'name': 'swagger-ui',
            'current': '5.20.0',
            'latest': '5.20.1'
        }
    ]
    
    with patch('builtins.open', mock_open(read_data=yaml.dump(mock_config))), \
         patch('os.environ', {'UPDATES_LIST': json.dumps(mock_updates)}), \
         patch('update_packages.update_pkgbuild') as mock_update, \
         patch('update_packages.commit_and_push') as mock_commit, \
         patch('update_packages.clone_aur_package') as mock_clone:
        
        # Create two mock repos for the two packages
        mock_repo1 = MagicMock()
        mock_repo1.working_dir = '../test-package'
        
        mock_repo2 = MagicMock()
        mock_repo2.working_dir = '../swagger-ui'
        
        # Return the appropriate mock repo based on the package name
        def mock_clone_side_effect(package_name):
            if package_name == 'test-package':
                return mock_repo1
            elif package_name == 'swagger-ui':
                return mock_repo2
            
        mock_clone.side_effect = mock_clone_side_effect
        
        main()
        
        # Check that update_pkgbuild was called for both packages
        assert mock_update.call_count == 2
        
        # Extract calls to verify parameters
        update_calls = mock_update.call_args_list
        
        # First call should be for test-package
        expected_config1 = mock_config['packages']['test-package'].copy()
        expected_config1['pkgbuild_path'] = os.path.join('../test-package', 'PKGBUILD')
        assert update_calls[0][0][0] == 'test-package'
        assert update_calls[0][0][1] == expected_config1
        assert update_calls[0][0][2] == '1.2.4'
        
        # Second call should be for swagger-ui
        expected_config2 = mock_config['packages']['swagger-ui'].copy()
        expected_config2['pkgbuild_path'] = os.path.join('../swagger-ui', 'PKGBUILD')
        assert update_calls[1][0][0] == 'swagger-ui'
        assert update_calls[1][0][1] == expected_config2
        assert update_calls[1][0][2] == '5.20.1'
        
        # Check that commit_and_push was called for both packages
        assert mock_commit.call_count == 2
        
        # Verify commit calls
        commit_calls = mock_commit.call_args_list
        
        # First call should be for test-package
        assert commit_calls[0][0][0] == 'test-package'
        assert commit_calls[0][0][1] == '1.2.4'
        assert commit_calls[0][0][2] == expected_config1['pkgbuild_path']
        assert commit_calls[0][0][3] == mock_repo1
        
        # Second call should be for swagger-ui
        assert commit_calls[1][0][0] == 'swagger-ui'
        assert commit_calls[1][0][1] == '5.20.1'
        assert commit_calls[1][0][2] == expected_config2['pkgbuild_path']
        assert commit_calls[1][0][3] == mock_repo2 