import datetime
import zipfile
from unittest.mock import patch

from gallery.utils.backup import create_backup


def test_backup_creates_zip(tmp_path):
    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()

    assert create_backup(web_folder, backup_folder) is True

    today = datetime.date.today().strftime("%Y%m%d")
    backup_path = backup_folder / f"backup-{today}.zip"

    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)


def test_backup_with_subdirectories(tmp_path):
    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()

    assert create_backup(web_folder, backup_folder) is True

    today = datetime.date.today().strftime("%Y%m%d")
    backup_path = backup_folder / f"backup-{today}.zip"

    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)


def test_backup_existing_file_is_not_overwritten(tmp_path):
    web_folder = tmp_path / "plots"
    web_folder.mkdir()
    (web_folder / "file1.txt").write_text("abc")

    backup_folder = tmp_path / "backups"
    backup_folder.mkdir()

    today = datetime.date.today().strftime("%Y%m%d")
    backup_path = backup_folder / f"backup-{today}.zip"
    backup_path.write_text("existing backup")

    assert create_backup(web_folder, backup_folder) is True
    assert backup_path.read_text() == "existing backup"


def test_backup_empty_folder(tmp_path):
    web_folder = tmp_path / "plots"
    web_folder.mkdir()

    backup_folder = tmp_path / "backups"
    backup_folder.mkdir()

    assert create_backup(web_folder, backup_folder) is True

    today = datetime.date.today().strftime("%Y%m%d")
    backup_path = backup_folder / f"backup-{today}.zip"

    assert backup_path.exists()
    with zipfile.ZipFile(backup_path, "r") as z:
        assert len(z.namelist()) == 0


def test_backup_nonexistent_web_folder(tmp_path):
    web_folder = tmp_path / "nonexistent_plots"
    backup_folder = tmp_path / "backups"
    backup_folder.mkdir()

    assert create_backup(web_folder, backup_folder) is True

    today = datetime.date.today().strftime("%Y%m%d")
    backup_path = backup_folder / f"backup-{today}.zip"

    assert backup_path.exists()
    with zipfile.ZipFile(backup_path, "r") as z:
        assert len(z.namelist()) == 0


@patch("datetime.date")
def test_backup_with_custom_date(mock_date, tmp_path):
    mock_date.today.return_value.strftime.return_value = "20230908"

    web_folder = tmp_path / "plots"
    web_folder.mkdir()
    (web_folder / "file1.txt").write_text("test")

    backup_folder = tmp_path / "backups"
    backup_folder.mkdir()

    assert create_backup(web_folder, backup_folder) is True

    backup_path = backup_folder / "backup-20230908.zip"
    assert backup_path.exists()


def test_backup_folder_creation(tmp_path):
    web_folder = tmp_path / "plots"
    web_folder.mkdir()
    (web_folder / "file1.txt").write_text("test")

    # Don't create backup folder - let create_backup() create it
    backup_folder = tmp_path / "new_backups"

    assert create_backup(web_folder, backup_folder) is True

    assert backup_folder.exists()
    assert backup_folder.is_dir()

    today = datetime.date.today().strftime("%Y%m%d")
    backup_path = backup_folder / f"backup-{today}.zip"
    assert backup_path.exists()
