import zipfile
import datetime
from unittest.mock import patch
from utils import backup


def test_backup_creates_zip(tmp_path, monkeypatch):
    # Setup fake web folder
    web_folder = tmp_path / 'plots'
    web_folder.mkdir()
    (web_folder / 'file1.txt').write_text('abc')
    (web_folder / 'file2.txt').write_text('def')
    backup_folder = tmp_path / 'backups'
    backup_folder.mkdir()

    # Patch the module variables
    monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
    monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)

    # Call the backup function
    backup.create_backup()
    
    # Check that backup was created
    today = datetime.date.today().strftime('%Y%m%d')
    backup_name = f'backup-{today}.zip'
    backup_path = backup_folder / backup_name

    assert backup_path.exists()
    with zipfile.ZipFile(backup_path, 'r') as z:
        names = z.namelist()
        assert any('file1.txt' in n for n in names)
        assert any('file2.txt' in n for n in names)
    
    # Cleanup: remove the backup file after test
    backup_path.unlink()


def test_backup_with_subdirectories(tmp_path, monkeypatch):
    # Setup fake web folder with subdirectories
    web_folder = tmp_path / 'plots'
    web_folder.mkdir()
    (web_folder / 'file1.txt').write_text('content1')
    
    subdir = web_folder / 'subdir'
    subdir.mkdir()
    (subdir / 'file2.txt').write_text('content2')
    
    nested_subdir = subdir / 'nested'
    nested_subdir.mkdir()
    (nested_subdir / 'file3.txt').write_text('content3')
    
    backup_folder = tmp_path / 'backups'
    backup_folder.mkdir()

    # Patch the module variables
    monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
    monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)

    # Call the backup function
    backup.create_backup()
    
    # Check that backup was created with all files
    today = datetime.date.today().strftime('%Y%m%d')
    backup_name = f'backup-{today}.zip'
    backup_path = backup_folder / backup_name

    assert backup_path.exists()
    with zipfile.ZipFile(backup_path, 'r') as z:
        names = z.namelist()
        assert any('file1.txt' in n for n in names)
        assert any('file2.txt' in n for n in names)
        assert any('file3.txt' in n for n in names)
    
    # Cleanup
    backup_path.unlink()


def test_backup_existing_file(tmp_path, monkeypatch, capsys):
    # Setup fake web folder
    web_folder = tmp_path / 'plots'
    web_folder.mkdir()
    (web_folder / 'file1.txt').write_text('abc')
    
    backup_folder = tmp_path / 'backups'
    backup_folder.mkdir()

    # Create existing backup file
    today = datetime.date.today().strftime('%Y%m%d')
    backup_name = f'backup-{today}.zip'
    backup_path = backup_folder / backup_name
    backup_path.write_text('existing backup')

    # Patch the module variables
    monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
    monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)

    # Call the backup function
    backup.create_backup()
    
    # Check that message about existing backup was printed
    captured = capsys.readouterr()
    assert f"Backup already exists: {backup_path}" in captured.out
    
    # Cleanup
    backup_path.unlink()


def test_backup_empty_folder(tmp_path, monkeypatch):
    # Setup empty web folder
    web_folder = tmp_path / 'plots'
    web_folder.mkdir()
    
    backup_folder = tmp_path / 'backups'
    backup_folder.mkdir()

    # Patch the module variables
    monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
    monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)

    # Call the backup function
    backup.create_backup()
    
    # Check that backup was created (empty)
    today = datetime.date.today().strftime('%Y%m%d')
    backup_name = f'backup-{today}.zip'
    backup_path = backup_folder / backup_name

    assert backup_path.exists()
    with zipfile.ZipFile(backup_path, 'r') as z:
        assert len(z.namelist()) == 0
    
    # Cleanup
    backup_path.unlink()


def test_backup_nonexistent_web_folder(tmp_path, monkeypatch):
    # Setup nonexistent web folder
    web_folder = tmp_path / 'nonexistent_plots'
    backup_folder = tmp_path / 'backups'
    backup_folder.mkdir()

    # Patch the module variables
    monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
    monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)

    # Call the backup function
    backup.create_backup()
    
    # Check that backup was created (empty since source doesn't exist)
    today = datetime.date.today().strftime('%Y%m%d')
    backup_name = f'backup-{today}.zip'
    backup_path = backup_folder / backup_name

    assert backup_path.exists()
    with zipfile.ZipFile(backup_path, 'r') as z:
        assert len(z.namelist()) == 0
    
    # Cleanup
    backup_path.unlink()


@patch('datetime.date')
def test_backup_with_custom_date(mock_date, tmp_path, monkeypatch):
    # Mock date to return a specific date
    mock_date.today.return_value.strftime.return_value = "20230908"
    
    # Setup fake web folder
    web_folder = tmp_path / 'plots'
    web_folder.mkdir()
    (web_folder / 'file1.txt').write_text('test')
    
    backup_folder = tmp_path / 'backups'
    backup_folder.mkdir()

    # Patch the module variables
    monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
    monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)

    # Call the backup function
    backup.create_backup()
    
    # Check that backup was created with custom date
    backup_path = backup_folder / "backup-20230908.zip"
    assert backup_path.exists()
    
    # Cleanup
    backup_path.unlink()


def test_backup_folder_creation(tmp_path, monkeypatch):
    # Setup fake web folder
    web_folder = tmp_path / 'plots'
    web_folder.mkdir()
    (web_folder / 'file1.txt').write_text('test')
    
    # Don't create backup folder - let function create it
    backup_folder = tmp_path / 'new_backups'

    # Patch the module variables
    monkeypatch.setattr(backup, 'WEB_FOLDER', web_folder)
    monkeypatch.setattr(backup, 'BACKUP_FOLDER', backup_folder)

    # Call the backup function
    backup.create_backup()
    
    # Check that backup folder was created
    assert backup_folder.exists()
    assert backup_folder.is_dir()
    
    # Check that backup file was created
    today = datetime.date.today().strftime('%Y%m%d')
    backup_name = f'backup-{today}.zip'
    backup_path = backup_folder / backup_name
    assert backup_path.exists()