"""Tests for app/tasks/send_to_all.py module."""

from unittest.mock import MagicMock, patch

import pytest

from app.tasks.send_to_all import (
    _should_upload_to_dropbox,
    _should_upload_to_email,
    _should_upload_to_ftp,
    _should_upload_to_google_drive,
    _should_upload_to_icloud,
    _should_upload_to_nextcloud,
    _should_upload_to_onedrive,
    _should_upload_to_paperless,
    _should_upload_to_s3,
    _should_upload_to_sftp,
    _should_upload_to_webdav,
    get_configured_services_from_validator,
    send_to_all_destinations,
)


@pytest.mark.unit
class TestShouldUploadFunctions:
    """Test the _should_upload_to_* helper functions."""

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_dropbox_all_configured(self, mock_settings):
        """Test Dropbox upload check when all credentials are configured."""
        mock_settings.dropbox_app_key = "key"
        mock_settings.dropbox_app_secret = "secret"
        mock_settings.dropbox_refresh_token = "token"

        assert _should_upload_to_dropbox() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_dropbox_missing_credentials(self, mock_settings):
        """Test Dropbox upload check when credentials are missing."""
        mock_settings.dropbox_app_key = None
        mock_settings.dropbox_app_secret = None
        mock_settings.dropbox_refresh_token = None

        assert _should_upload_to_dropbox() is False

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_nextcloud_configured(self, mock_settings):
        """Test Nextcloud upload check."""
        mock_settings.nextcloud_upload_url = "https://nextcloud.example.com"
        mock_settings.nextcloud_username = "user"
        mock_settings.nextcloud_password = "pass"

        assert _should_upload_to_nextcloud() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_paperless_configured(self, mock_settings):
        """Test Paperless upload check."""
        mock_settings.paperless_ngx_api_token = "token"
        mock_settings.paperless_host = "https://paperless.example.com"

        assert _should_upload_to_paperless() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_google_drive_oauth(self, mock_settings):
        """Test Google Drive upload check with OAuth."""
        mock_settings.google_drive_use_oauth = True
        mock_settings.google_drive_client_id = "client_id"
        mock_settings.google_drive_client_secret = "client_secret"
        mock_settings.google_drive_refresh_token = "refresh_token"
        mock_settings.google_drive_folder_id = "folder_id"

        assert _should_upload_to_google_drive() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_google_drive_service_account(self, mock_settings):
        """Test Google Drive upload check with service account."""
        mock_settings.google_drive_use_oauth = False
        mock_settings.google_drive_credentials_json = '{"type": "service_account"}'
        mock_settings.google_drive_folder_id = "folder_id"

        assert _should_upload_to_google_drive() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_webdav_configured(self, mock_settings):
        """Test WebDAV upload check."""
        mock_settings.webdav_url = "https://webdav.example.com"
        mock_settings.webdav_username = "user"
        mock_settings.webdav_password = "pass"

        assert _should_upload_to_webdav() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_ftp_configured(self, mock_settings):
        """Test FTP upload check."""
        mock_settings.ftp_host = "ftp.example.com"
        mock_settings.ftp_username = "user"
        mock_settings.ftp_password = "pass"

        assert _should_upload_to_ftp() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_sftp_with_password(self, mock_settings):
        """Test SFTP upload check with password auth."""
        mock_settings.sftp_host = "sftp.example.com"
        mock_settings.sftp_username = "user"
        mock_settings.sftp_password = "pass"
        mock_settings.sftp_private_key = None

        assert _should_upload_to_sftp() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_sftp_with_key(self, mock_settings):
        """Test SFTP upload check with key auth."""
        mock_settings.sftp_host = "sftp.example.com"
        mock_settings.sftp_username = "user"
        mock_settings.sftp_password = None
        mock_settings.sftp_private_key = "/path/to/key"

        assert _should_upload_to_sftp() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_email_configured(self, mock_settings):
        """Test email upload check."""
        mock_settings.dest_email_host = "smtp.example.com"
        mock_settings.dest_email_username = "user"
        mock_settings.dest_email_password = "pass"
        mock_settings.dest_email_default_recipient = "recipient@example.com"

        assert _should_upload_to_email() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_onedrive_configured(self, mock_settings):
        """Test OneDrive upload check."""
        mock_settings.onedrive_client_id = "client_id"
        mock_settings.onedrive_client_secret = "client_secret"
        mock_settings.onedrive_refresh_token = "refresh_token"

        assert _should_upload_to_onedrive() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_s3_configured(self, mock_settings):
        """Test S3 upload check."""
        mock_settings.s3_bucket_name = "my-bucket"
        mock_settings.aws_access_key_id = "key_id"
        mock_settings.aws_secret_access_key = "secret_key"

        assert _should_upload_to_s3() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_icloud_configured(self, mock_settings):
        """Test iCloud upload check."""
        mock_settings.icloud_username = "user@example.com"
        mock_settings.icloud_password = "app-specific-password"

        assert _should_upload_to_icloud() is True

    @patch("app.tasks.send_to_all.settings")
    def test_should_upload_to_icloud_not_configured(self, mock_settings):
        """Test iCloud upload check when not configured."""
        mock_settings.icloud_username = None
        mock_settings.icloud_password = None

        assert _should_upload_to_icloud() is False


@pytest.mark.unit
class TestShouldUploadEnabledFlag:
    """Test that the _should_upload_to_* functions respect the explicit enabled flag."""

    @patch("app.tasks.send_to_all.settings")
    def test_dropbox_disabled_with_credentials(self, mock_settings):
        """Test Dropbox upload is blocked when disabled even with valid credentials."""
        mock_settings.dropbox_enabled = False
        mock_settings.dropbox_app_key = "key"
        mock_settings.dropbox_app_secret = "secret"
        mock_settings.dropbox_refresh_token = "token"

        assert _should_upload_to_dropbox() is False

    @patch("app.tasks.send_to_all.settings")
    def test_nextcloud_disabled_with_credentials(self, mock_settings):
        """Test Nextcloud upload is blocked when disabled even with valid credentials."""
        mock_settings.nextcloud_enabled = False
        mock_settings.nextcloud_upload_url = "https://nextcloud.example.com"
        mock_settings.nextcloud_username = "user"
        mock_settings.nextcloud_password = "pass"

        assert _should_upload_to_nextcloud() is False

    @patch("app.tasks.send_to_all.settings")
    def test_paperless_disabled_with_credentials(self, mock_settings):
        """Test Paperless upload is blocked when disabled even with valid credentials."""
        mock_settings.paperless_enabled = False
        mock_settings.paperless_ngx_api_token = "token"
        mock_settings.paperless_host = "https://paperless.example.com"

        assert _should_upload_to_paperless() is False

    @patch("app.tasks.send_to_all.settings")
    def test_google_drive_disabled_with_credentials(self, mock_settings):
        """Test Google Drive upload is blocked when disabled even with valid credentials."""
        mock_settings.google_drive_enabled = False
        mock_settings.google_drive_use_oauth = False
        mock_settings.google_drive_credentials_json = '{"type": "service_account"}'
        mock_settings.google_drive_folder_id = "folder_id"

        assert _should_upload_to_google_drive() is False

    @patch("app.tasks.send_to_all.settings")
    def test_webdav_disabled_with_credentials(self, mock_settings):
        """Test WebDAV upload is blocked when disabled even with valid credentials."""
        mock_settings.webdav_enabled = False
        mock_settings.webdav_url = "https://webdav.example.com"
        mock_settings.webdav_username = "user"
        mock_settings.webdav_password = "pass"

        assert _should_upload_to_webdav() is False

    @patch("app.tasks.send_to_all.settings")
    def test_ftp_disabled_with_credentials(self, mock_settings):
        """Test FTP upload is blocked when disabled even with valid credentials."""
        mock_settings.ftp_enabled = False
        mock_settings.ftp_host = "ftp.example.com"
        mock_settings.ftp_username = "user"
        mock_settings.ftp_password = "pass"

        assert _should_upload_to_ftp() is False

    @patch("app.tasks.send_to_all.settings")
    def test_sftp_disabled_with_credentials(self, mock_settings):
        """Test SFTP upload is blocked when disabled even with valid credentials."""
        mock_settings.sftp_enabled = False
        mock_settings.sftp_host = "sftp.example.com"
        mock_settings.sftp_username = "user"
        mock_settings.sftp_password = "pass"
        mock_settings.sftp_private_key = None

        assert _should_upload_to_sftp() is False

    @patch("app.tasks.send_to_all.settings")
    def test_email_disabled_with_credentials(self, mock_settings):
        """Test email upload is blocked when disabled even with valid credentials."""
        mock_settings.dest_email_enabled = False
        mock_settings.dest_email_host = "smtp.example.com"
        mock_settings.dest_email_username = "user"
        mock_settings.dest_email_password = "pass"
        mock_settings.dest_email_default_recipient = "recipient@example.com"

        assert _should_upload_to_email() is False

    @patch("app.tasks.send_to_all.settings")
    def test_onedrive_disabled_with_credentials(self, mock_settings):
        """Test OneDrive upload is blocked when disabled even with valid credentials."""
        mock_settings.onedrive_enabled = False
        mock_settings.onedrive_client_id = "client_id"
        mock_settings.onedrive_client_secret = "client_secret"
        mock_settings.onedrive_refresh_token = "refresh_token"

        assert _should_upload_to_onedrive() is False

    @patch("app.tasks.send_to_all.settings")
    def test_s3_disabled_with_credentials(self, mock_settings):
        """Test S3 upload is blocked when disabled even with valid credentials."""
        mock_settings.s3_enabled = False
        mock_settings.s3_bucket_name = "my-bucket"
        mock_settings.aws_access_key_id = "key_id"
        mock_settings.aws_secret_access_key = "secret_key"

        assert _should_upload_to_s3() is False

    @patch("app.tasks.send_to_all.settings")
    def test_icloud_disabled_with_credentials(self, mock_settings):
        """Test iCloud upload is blocked when disabled even with valid credentials."""
        mock_settings.icloud_enabled = False
        mock_settings.icloud_username = "user@example.com"
        mock_settings.icloud_password = "app-specific-password"

        assert _should_upload_to_icloud() is False


@pytest.mark.unit
class TestGetConfiguredServicesFromValidator:
    """Test get_configured_services_from_validator function."""

    @patch("app.tasks.send_to_all.get_provider_status")
    def test_returns_configured_services(self, mock_get_status):
        """Test that configured services are returned correctly."""
        mock_get_status.return_value = {
            "Dropbox": {"configured": True, "enabled": True},
            "NextCloud": {"configured": False, "enabled": True},
            "S3 Storage": {"configured": True, "enabled": True},
        }

        result = get_configured_services_from_validator()

        assert result["dropbox"] is True
        assert result["nextcloud"] is False
        assert result["s3"] is True

    @patch("app.tasks.send_to_all.get_provider_status")
    def test_handles_missing_providers(self, mock_get_status):
        """Test handling when some providers are not in status."""
        mock_get_status.return_value = {
            "Dropbox": {"configured": True, "enabled": True},
        }

        result = get_configured_services_from_validator()

        assert result["dropbox"] is True
        # Other services not in result

    @patch("app.tasks.send_to_all.get_provider_status")
    def test_configured_but_disabled_service_not_active(self, mock_get_status):
        """Test that a configured but disabled service is not returned as active."""
        mock_get_status.return_value = {
            "Dropbox": {"configured": True, "enabled": False},
            "S3 Storage": {"configured": True, "enabled": True},
        }

        result = get_configured_services_from_validator()

        assert result["dropbox"] is False
        assert result["s3"] is True

    @patch("app.tasks.send_to_all.get_provider_status")
    def test_missing_enabled_field_defaults_to_true_for_backward_compatibility(self, mock_get_status):
        """Test that missing 'enabled' key defaults to True (backward compatible)."""
        mock_get_status.return_value = {
            "Dropbox": {"configured": True},
        }

        result = get_configured_services_from_validator()

        assert result["dropbox"] is True


@pytest.mark.unit
class TestSendToAllDestinations:
    """Test send_to_all_destinations task."""

    @patch("app.tasks.send_to_all.log_task_progress")
    def test_file_not_found_error(self, mock_log):
        """Test that FileNotFoundError is raised when file doesn't exist."""
        result = send_to_all_destinations.apply(args=["/nonexistent/file.pdf"])

        # When task raises an exception, result.failed() returns True
        assert result.failed()
        # The exception should be FileNotFoundError
        assert isinstance(result.result, FileNotFoundError)

    @patch("app.tasks.send_to_all.SessionLocal")
    @patch("app.tasks.send_to_all.log_task_progress")
    @patch("app.tasks.send_to_all.settings")
    @patch("app.tasks.send_to_all._should_upload_to_dropbox")
    @patch("app.tasks.send_to_all._should_upload_to_nextcloud")
    @patch("app.tasks.send_to_all._should_upload_to_paperless")
    @patch("app.tasks.send_to_all._should_upload_to_google_drive")
    @patch("app.tasks.send_to_all._should_upload_to_webdav")
    @patch("app.tasks.send_to_all._should_upload_to_ftp")
    @patch("app.tasks.send_to_all._should_upload_to_sftp")
    @patch("app.tasks.send_to_all._should_upload_to_email")
    @patch("app.tasks.send_to_all._should_upload_to_onedrive")
    @patch("app.tasks.send_to_all._should_upload_to_sharepoint")
    @patch("app.tasks.send_to_all._should_upload_to_icloud")
    @patch("app.tasks.send_to_all._should_upload_to_s3")
    @patch("app.tasks.send_to_all.upload_to_dropbox")
    def test_queues_single_configured_service(
        self,
        mock_upload,
        mock_s3,
        mock_icloud,
        mock_sharepoint,
        mock_onedrive,
        mock_email,
        mock_sftp,
        mock_ftp,
        mock_webdav,
        mock_google,
        mock_paperless,
        mock_nextcloud,
        mock_should,
        mock_settings,
        mock_log,
        mock_session_local,
        tmp_path,
    ):
        """Test queueing upload to a single configured service."""
        test_file = tmp_path / "test.pdf"
        test_file.write_text("test")

        mock_should.return_value = True
        # Mock all other services to return False
        mock_nextcloud.return_value = False
        mock_paperless.return_value = False
        mock_google.return_value = False
        mock_webdav.return_value = False
        mock_ftp.return_value = False
        mock_sftp.return_value = False
        mock_email.return_value = False
        mock_onedrive.return_value = False
        mock_s3.return_value = False
        mock_sharepoint.return_value = False
        mock_icloud.return_value = False
        mock_upload.delay.return_value = MagicMock(id="task-123")

        result = send_to_all_destinations.apply(args=[str(test_file), False, 1])

        assert result.result["status"] == "Queued"
        mock_upload.delay.assert_called_once()

    @patch("app.tasks.send_to_all.SessionLocal")
    @patch("app.tasks.send_to_all.log_task_progress")
    @patch("app.tasks.send_to_all.settings")
    @patch("app.tasks.send_to_all._should_upload_to_dropbox")
    @patch("app.tasks.send_to_all._should_upload_to_icloud")
    @patch("app.tasks.send_to_all._should_upload_to_sharepoint")
    @patch("app.tasks.send_to_all._should_upload_to_s3")
    @patch("app.tasks.send_to_all._should_upload_to_nextcloud")
    @patch("app.tasks.send_to_all._should_upload_to_paperless")
    @patch("app.tasks.send_to_all._should_upload_to_google_drive")
    @patch("app.tasks.send_to_all._should_upload_to_webdav")
    @patch("app.tasks.send_to_all._should_upload_to_ftp")
    @patch("app.tasks.send_to_all._should_upload_to_sftp")
    @patch("app.tasks.send_to_all._should_upload_to_email")
    @patch("app.tasks.send_to_all._should_upload_to_onedrive")
    @patch("app.tasks.send_to_all.upload_to_dropbox")
    @patch("app.tasks.send_to_all.upload_to_s3")
    def test_queues_multiple_services(
        self,
        mock_s3_upload,
        mock_dropbox_upload,
        mock_onedrive,
        mock_email,
        mock_sftp,
        mock_ftp,
        mock_webdav,
        mock_google,
        mock_paperless,
        mock_nextcloud,
        mock_should_s3,
        mock_sharepoint,
        mock_icloud,
        mock_should_dropbox,
        mock_settings,
        mock_log,
        mock_session_local,
        tmp_path,
    ):
        """Test queueing uploads to multiple services."""
        test_file = tmp_path / "test.pdf"
        test_file.write_text("test")

        mock_should_dropbox.return_value = True
        mock_should_s3.return_value = True
        # Mock all other services to return False
        mock_nextcloud.return_value = False
        mock_paperless.return_value = False
        mock_google.return_value = False
        mock_webdav.return_value = False
        mock_ftp.return_value = False
        mock_sftp.return_value = False
        mock_email.return_value = False
        mock_onedrive.return_value = False
        mock_sharepoint.return_value = False
        mock_icloud.return_value = False
        mock_dropbox_upload.delay.return_value = MagicMock(id="dropbox-task")
        mock_s3_upload.delay.return_value = MagicMock(id="s3-task")

        result = send_to_all_destinations.apply(args=[str(test_file), False, 1])

        assert result.result["status"] == "Queued"
        mock_dropbox_upload.delay.assert_called_once()
        mock_s3_upload.delay.assert_called_once()

    @patch("app.tasks.send_to_all.SessionLocal")
    @patch("app.tasks.send_to_all.log_task_progress")
    @patch("app.tasks.send_to_all.settings")
    @patch("app.tasks.send_to_all._should_upload_to_dropbox")
    @patch("app.tasks.send_to_all._should_upload_to_nextcloud")
    @patch("app.tasks.send_to_all._should_upload_to_paperless")
    @patch("app.tasks.send_to_all._should_upload_to_google_drive")
    @patch("app.tasks.send_to_all._should_upload_to_webdav")
    @patch("app.tasks.send_to_all._should_upload_to_ftp")
    @patch("app.tasks.send_to_all._should_upload_to_sftp")
    @patch("app.tasks.send_to_all._should_upload_to_email")
    @patch("app.tasks.send_to_all._should_upload_to_onedrive")
    @patch("app.tasks.send_to_all._should_upload_to_sharepoint")
    @patch("app.tasks.send_to_all._should_upload_to_icloud")
    @patch("app.tasks.send_to_all._should_upload_to_s3")
    def test_skips_unconfigured_services(
        self,
        mock_s3,
        mock_icloud,
        mock_sharepoint,
        mock_onedrive,
        mock_email,
        mock_sftp,
        mock_ftp,
        mock_webdav,
        mock_google,
        mock_paperless,
        mock_nextcloud,
        mock_should,
        mock_settings,
        mock_log,
        mock_session_local,
        tmp_path,
    ):
        """Test that unconfigured services are skipped."""
        test_file = tmp_path / "test.pdf"
        test_file.write_text("test")

        # Set all _should_upload_* functions to return False
        mock_should.return_value = False
        mock_nextcloud.return_value = False
        mock_paperless.return_value = False
        mock_google.return_value = False
        mock_webdav.return_value = False
        mock_ftp.return_value = False
        mock_sftp.return_value = False
        mock_email.return_value = False
        mock_onedrive.return_value = False
        mock_s3.return_value = False
        mock_sharepoint.return_value = False
        mock_icloud.return_value = False

        result = send_to_all_destinations.apply(args=[str(test_file), False, 1])

        # No uploads should be queued
        assert result.result["status"] == "Queued"
        # Check that message indicates 0 uploads
        assert "0 upload" in result.result["tasks"] or len(result.result["tasks"]) == 0

    @patch("app.tasks.send_to_all.log_task_progress")
    @patch("app.tasks.send_to_all.SessionLocal")
    @patch("app.tasks.send_to_all.settings")
    @patch("app.tasks.send_to_all._should_upload_to_dropbox")
    @patch("app.tasks.send_to_all._should_upload_to_nextcloud")
    @patch("app.tasks.send_to_all._should_upload_to_paperless")
    @patch("app.tasks.send_to_all._should_upload_to_google_drive")
    @patch("app.tasks.send_to_all._should_upload_to_webdav")
    @patch("app.tasks.send_to_all._should_upload_to_ftp")
    @patch("app.tasks.send_to_all._should_upload_to_sftp")
    @patch("app.tasks.send_to_all._should_upload_to_email")
    @patch("app.tasks.send_to_all._should_upload_to_onedrive")
    @patch("app.tasks.send_to_all._should_upload_to_sharepoint")
    @patch("app.tasks.send_to_all._should_upload_to_icloud")
    @patch("app.tasks.send_to_all._should_upload_to_s3")
    @patch("app.tasks.send_to_all.upload_to_dropbox")
    def test_with_file_id_parameter(
        self,
        mock_upload,
        mock_s3,
        mock_icloud,
        mock_sharepoint,
        mock_onedrive,
        mock_email,
        mock_sftp,
        mock_ftp,
        mock_webdav,
        mock_google,
        mock_paperless,
        mock_nextcloud,
        mock_should,
        mock_settings,
        mock_session_local,
        mock_log,
        tmp_path,
    ):
        """Test send_to_all with explicit file_id parameter."""
        test_file = tmp_path / "test.pdf"
        test_file.write_text("test")

        mock_should.return_value = True
        # Mock all other services to return False
        mock_nextcloud.return_value = False
        mock_paperless.return_value = False
        mock_google.return_value = False
        mock_webdav.return_value = False
        mock_ftp.return_value = False
        mock_sftp.return_value = False
        mock_email.return_value = False
        mock_onedrive.return_value = False
        mock_s3.return_value = False
        mock_sharepoint.return_value = False
        mock_icloud.return_value = False
        mock_upload.delay.return_value = MagicMock(id="task-123")

        result = send_to_all_destinations.apply(args=[str(test_file), False, 42])

        mock_upload.delay.assert_called_once()
        # Verify file_id was passed to the upload task
        call_kwargs = mock_upload.delay.call_args[1]
        assert call_kwargs.get("file_id") == 42

    @patch("app.tasks.send_to_all.SessionLocal")
    @patch("app.tasks.send_to_all.log_task_progress")
    @patch("app.tasks.send_to_all.settings")
    @patch("app.tasks.send_to_all._should_upload_to_dropbox")
    @patch("app.tasks.send_to_all._should_upload_to_nextcloud")
    @patch("app.tasks.send_to_all._should_upload_to_paperless")
    @patch("app.tasks.send_to_all._should_upload_to_google_drive")
    @patch("app.tasks.send_to_all._should_upload_to_webdav")
    @patch("app.tasks.send_to_all._should_upload_to_ftp")
    @patch("app.tasks.send_to_all._should_upload_to_sftp")
    @patch("app.tasks.send_to_all._should_upload_to_email")
    @patch("app.tasks.send_to_all._should_upload_to_onedrive")
    @patch("app.tasks.send_to_all._should_upload_to_sharepoint")
    @patch("app.tasks.send_to_all._should_upload_to_icloud")
    @patch("app.tasks.send_to_all._should_upload_to_s3")
    @patch("app.tasks.send_to_all.get_configured_services_from_validator")
    @patch("app.tasks.send_to_all.upload_to_dropbox")
    def test_uses_validator_when_enabled(
        self,
        mock_upload,
        mock_validator,
        mock_s3,
        mock_icloud,
        mock_sharepoint,
        mock_onedrive,
        mock_email,
        mock_sftp,
        mock_ftp,
        mock_webdav,
        mock_google,
        mock_paperless,
        mock_nextcloud,
        mock_should_dropbox,
        mock_settings,
        mock_log,
        mock_session_local,
        tmp_path,
    ):
        """Test that validator is used when use_validator=True."""
        test_file = tmp_path / "test.pdf"
        test_file.write_text("test")

        mock_validator.return_value = {"dropbox": True}
        # Mock all should_upload functions to return False (they won't be called when validator is used, but just in case)
        mock_should_dropbox.return_value = False
        mock_nextcloud.return_value = False
        mock_paperless.return_value = False
        mock_google.return_value = False
        mock_webdav.return_value = False
        mock_ftp.return_value = False
        mock_sftp.return_value = False
        mock_email.return_value = False
        mock_onedrive.return_value = False
        mock_s3.return_value = False
        mock_sharepoint.return_value = False
        mock_icloud.return_value = False
        mock_upload.delay.return_value = MagicMock(id="task-123")

        result = send_to_all_destinations.apply(args=[str(test_file), True, 1])

        mock_validator.assert_called_once()
        mock_upload.delay.assert_called_once()

    @patch("app.tasks.send_to_all.SessionLocal")
    @patch("app.tasks.send_to_all.log_task_progress")
    @patch("app.tasks.send_to_all.settings")
    @patch("app.tasks.send_to_all._should_upload_to_dropbox")
    @patch("app.tasks.send_to_all._should_upload_to_nextcloud")
    @patch("app.tasks.send_to_all._should_upload_to_paperless")
    @patch("app.tasks.send_to_all._should_upload_to_google_drive")
    @patch("app.tasks.send_to_all._should_upload_to_webdav")
    @patch("app.tasks.send_to_all._should_upload_to_ftp")
    @patch("app.tasks.send_to_all._should_upload_to_sftp")
    @patch("app.tasks.send_to_all._should_upload_to_email")
    @patch("app.tasks.send_to_all._should_upload_to_onedrive")
    @patch("app.tasks.send_to_all._should_upload_to_sharepoint")
    @patch("app.tasks.send_to_all._should_upload_to_icloud")
    @patch("app.tasks.send_to_all._should_upload_to_s3")
    @patch("app.tasks.send_to_all.get_configured_services_from_validator")
    def test_validator_exception_fallback(
        self,
        mock_validator,
        mock_s3,
        mock_icloud,
        mock_sharepoint,
        mock_onedrive,
        mock_email,
        mock_sftp,
        mock_ftp,
        mock_webdav,
        mock_google,
        mock_paperless,
        mock_nextcloud,
        mock_should_dropbox,
        mock_settings,
        mock_log,
        mock_session_local,
        tmp_path,
    ):
        """Test fallback to individual checks when validator fails."""
        test_file = tmp_path / "test.pdf"
        test_file.write_text("test")

        mock_validator.side_effect = Exception("Validator error")
        # Set all _should_upload_* functions to return False
        mock_should_dropbox.return_value = False
        mock_nextcloud.return_value = False
        mock_paperless.return_value = False
        mock_google.return_value = False
        mock_webdav.return_value = False
        mock_ftp.return_value = False
        mock_sftp.return_value = False
        mock_email.return_value = False
        mock_onedrive.return_value = False
        mock_s3.return_value = False
        mock_sharepoint.return_value = False
        mock_icloud.return_value = False

        # Should not raise, should fall back to individual checks
        result = send_to_all_destinations.apply(args=[str(test_file), True, 1])

        assert result.result["status"] == "Queued"

    @patch("app.tasks.send_to_all.SessionLocal")
    @patch("app.tasks.send_to_all.log_task_progress")
    @patch("app.tasks.send_to_all.settings")
    @patch("app.tasks.send_to_all._should_upload_to_dropbox")
    @patch("app.tasks.send_to_all._should_upload_to_nextcloud")
    @patch("app.tasks.send_to_all._should_upload_to_paperless")
    @patch("app.tasks.send_to_all._should_upload_to_google_drive")
    @patch("app.tasks.send_to_all._should_upload_to_webdav")
    @patch("app.tasks.send_to_all._should_upload_to_ftp")
    @patch("app.tasks.send_to_all._should_upload_to_sftp")
    @patch("app.tasks.send_to_all._should_upload_to_email")
    @patch("app.tasks.send_to_all._should_upload_to_onedrive")
    @patch("app.tasks.send_to_all._should_upload_to_sharepoint")
    @patch("app.tasks.send_to_all._should_upload_to_icloud")
    @patch("app.tasks.send_to_all._should_upload_to_s3")
    @patch("app.tasks.send_to_all.upload_to_dropbox")
    def test_handles_upload_task_queue_error(
        self,
        mock_upload,
        mock_s3,
        mock_icloud,
        mock_sharepoint,
        mock_onedrive,
        mock_email,
        mock_sftp,
        mock_ftp,
        mock_webdav,
        mock_google,
        mock_paperless,
        mock_nextcloud,
        mock_should,
        mock_settings,
        mock_log,
        mock_session_local,
        tmp_path,
    ):
        """Test handling when queueing upload task fails."""
        test_file = tmp_path / "test.pdf"
        test_file.write_text("test")

        mock_should.return_value = True
        # Mock all other services to return False
        mock_nextcloud.return_value = False
        mock_paperless.return_value = False
        mock_google.return_value = False
        mock_webdav.return_value = False
        mock_ftp.return_value = False
        mock_sftp.return_value = False
        mock_email.return_value = False
        mock_onedrive.return_value = False
        mock_s3.return_value = False
        mock_sharepoint.return_value = False
        mock_icloud.return_value = False
        mock_upload.delay.side_effect = Exception("Queue error")

        # Should not raise, should log error
        result = send_to_all_destinations.apply(args=[str(test_file), False, 1])

        assert result.result["status"] == "Queued"
        # Error should be recorded in results
        assert "dropbox_error" in result.result["tasks"]

    @patch("app.tasks.send_to_all._should_upload_to_icloud")
    @patch("app.tasks.send_to_all._should_upload_to_sharepoint")
    @patch("app.tasks.send_to_all._should_upload_to_s3")
    @patch("app.tasks.send_to_all._should_upload_to_onedrive")
    @patch("app.tasks.send_to_all._should_upload_to_email")
    @patch("app.tasks.send_to_all._should_upload_to_sftp")
    @patch("app.tasks.send_to_all._should_upload_to_ftp")
    @patch("app.tasks.send_to_all._should_upload_to_webdav")
    @patch("app.tasks.send_to_all._should_upload_to_google_drive")
    @patch("app.tasks.send_to_all._should_upload_to_paperless")
    @patch("app.tasks.send_to_all._should_upload_to_nextcloud")
    @patch("app.tasks.send_to_all._should_upload_to_dropbox")
    @patch("app.tasks.send_to_all.log_task_progress")
    @patch("app.tasks.send_to_all.SessionLocal")
    @patch("app.tasks.send_to_all.settings")
    def test_fallback_file_id_lookup(
        self,
        mock_settings,
        mock_session_local,
        mock_log,
        mock_dropbox,
        mock_nextcloud,
        mock_paperless,
        mock_google,
        mock_webdav,
        mock_ftp,
        mock_sftp,
        mock_email,
        mock_onedrive,
        mock_s3,
        mock_sharepoint,
        mock_icloud,
        tmp_path,
    ):
        """Test file_id lookup fallback when not provided."""
        from app.models import FileRecord

        test_file = tmp_path / "test.pdf"
        test_file.write_text("test")

        mock_settings.workdir = str(tmp_path)

        # Disable all upload services — this test only checks the DB lookup fallback
        mock_dropbox.return_value = False
        mock_nextcloud.return_value = False
        mock_paperless.return_value = False
        mock_google.return_value = False
        mock_webdav.return_value = False
        mock_ftp.return_value = False
        mock_sftp.return_value = False
        mock_email.return_value = False
        mock_onedrive.return_value = False
        mock_s3.return_value = False
        mock_sharepoint.return_value = False
        mock_icloud.return_value = False

        # Mock database session
        mock_db = MagicMock()
        mock_query = MagicMock()
        mock_file_record = MagicMock(spec=FileRecord)
        mock_file_record.id = 123
        mock_query.first.return_value = mock_file_record
        mock_db.query.return_value.filter.return_value = mock_query
        mock_session_local.return_value.__enter__.return_value = mock_db

        result = send_to_all_destinations.apply(args=[str(test_file), False, None])

        # Should attempt database lookup
        mock_db.query.assert_called()

    @patch("app.tasks.send_to_all.SessionLocal")
    @patch("app.tasks.send_to_all.log_task_progress")
    @patch("app.tasks.send_to_all.settings")
    @patch("app.tasks.send_to_all._should_upload_to_dropbox")
    @patch("app.tasks.send_to_all._should_upload_to_nextcloud")
    @patch("app.tasks.send_to_all._should_upload_to_paperless")
    @patch("app.tasks.send_to_all._should_upload_to_google_drive")
    @patch("app.tasks.send_to_all._should_upload_to_webdav")
    @patch("app.tasks.send_to_all._should_upload_to_ftp")
    @patch("app.tasks.send_to_all._should_upload_to_sftp")
    @patch("app.tasks.send_to_all._should_upload_to_email")
    @patch("app.tasks.send_to_all._should_upload_to_onedrive")
    @patch("app.tasks.send_to_all._should_upload_to_sharepoint")
    @patch("app.tasks.send_to_all._should_upload_to_icloud")
    @patch("app.tasks.send_to_all._should_upload_to_s3")
    def test_should_upload_check_exception_handling(
        self,
        mock_s3,
        mock_icloud,
        mock_sharepoint,
        mock_onedrive,
        mock_email,
        mock_sftp,
        mock_ftp,
        mock_webdav,
        mock_google,
        mock_paperless,
        mock_nextcloud,
        mock_should,
        mock_settings,
        mock_log,
        mock_session_local,
        tmp_path,
    ):
        """Test that exceptions in should_upload checks are handled."""
        test_file = tmp_path / "test.pdf"
        test_file.write_text("test")

        mock_should.side_effect = Exception("Configuration check error")
        # Mock all other services to return False
        mock_nextcloud.return_value = False
        mock_paperless.return_value = False
        mock_google.return_value = False
        mock_webdav.return_value = False
        mock_ftp.return_value = False
        mock_sftp.return_value = False
        mock_email.return_value = False
        mock_onedrive.return_value = False
        mock_s3.return_value = False
        mock_sharepoint.return_value = False
        mock_icloud.return_value = False

        # Should not raise, should treat as not configured
        result = send_to_all_destinations.apply(args=[str(test_file), False, 1])

        assert result.result["status"] == "Queued"
