from unittest.mock import Mock, patch

from urarovite.validators.bulk_rename_spreadsheets import (
    BulkRenameSpreadsheetsValidator,
    run,
)


class TestBulkRenameSpreadsheetsValidator:
    def setup_method(self):
        self.validator = BulkRenameSpreadsheetsValidator()

    def test_validate_missing_args(self):
        """
        Ensure validator reports an error when required parameters are missing.
        """
        mock_service = Mock()

        result = self.validator.validate(
            sheets_service=mock_service,
            sheet_id="",
            mode="fix",
            template_sheet_url=None,
            range=None,
        )

        assert len(result["errors"]) == 1
        assert "Missing template_sheet_url or range" in result["errors"][0]
        assert result["automated_log"] == "Completed with errors"
        assert result["issues_found"] == 1
        assert result["fixes_applied"] == 0

    @patch("urarovite.utils.sheets.rename_spreadsheet_title")
    @patch("urarovite.utils.sheets.get_sheet_values")
    def test_validate_success_with_renamed(self, mock_get_values, mock_rename):
        """
        When operation succeeds and some rows are renamed, fixes are counted and success log is set.
        """
        mock_get_values.return_value = {
            "success": True,
            "values": [
                ["https://docs.google.com/spreadsheets/d/AAA/edit", "New Title 1"],
                ["https://docs.google.com/spreadsheets/d/BBB/edit", "New Title 2"],
                ["https://docs.google.com/spreadsheets/d/CCC/edit", "New Title 3"],
            ],
            "rows": 3,
            "cols": 2,
            "error": None,
        }
        mock_rename.return_value = {"success": True}

        mock_service = Mock()

        result = self.validator.validate(
            sheets_service=mock_service,
            sheet_id="",
            mode="fix",
            template_sheet_url="https://docs.google.com/spreadsheets/d/template/edit",
            range="A1:B10",
        )

        assert result["fixes_applied"] == 3
        assert result["issues_found"] == 0
        assert result["errors"] == []
        assert result["automated_log"] == "Renamed successfully"

    @patch("urarovite.utils.sheets.rename_spreadsheet_title")
    @patch("urarovite.utils.sheets.get_sheet_values")
    def test_validate_success_with_zero_renamed(self, mock_get_values, mock_rename):
        """
        When operation succeeds but zero rows are processed, set appropriate log without errors.
        """
        mock_get_values.return_value = {
            "success": True,
            "values": [
                [],
                ["https://docs.google.com/spreadsheets/d/AAA/edit"],
                [None, "Title without URL"],
            ],
            "rows": 3,
            "cols": 2,
            "error": None,
        }
        mock_rename.return_value = {"success": True}

        mock_service = Mock()

        result = self.validator.validate(
            sheets_service=mock_service,
            sheet_id="",
            mode="fix",
            template_sheet_url="https://docs.google.com/spreadsheets/d/template/edit",
            range="A1:B10",
        )

        assert result["fixes_applied"] == 0
        assert result["issues_found"] == 0
        assert result["errors"] == []
        assert result["automated_log"] == "No rows processed"

    @patch("urarovite.utils.sheets.rename_spreadsheet_title")
    @patch("urarovite.utils.sheets.get_sheet_values")
    def test_validate_failure_with_failed_list(self, mock_get_values, mock_rename):
        """
        When operation fails with a list of per-row failures, report each as an error and count issues.
        """
        mock_get_values.return_value = {
            "success": True,
            "values": [
                ["https://docs.google.com/spreadsheets/d/AAA/edit", "Title 1"],
                ["https://docs.google.com/spreadsheets/d/BBB/edit", "Title 2"],
            ],
            "rows": 2,
            "cols": 2,
            "error": None,
        }
        mock_rename.side_effect = [
            {"success": False, "error": "not_found"},
            {"success": False, "error": "permission_denied"},
        ]

        mock_service = Mock()

        result = self.validator.validate(
            sheets_service=mock_service,
            sheet_id="",
            mode="fix",
            template_sheet_url="https://docs.google.com/spreadsheets/d/template/edit",
            range="A1:B10",
        )

        assert result["issues_found"] == 2
        assert "not_found" in result["errors"]
        assert "permission_denied" in result["errors"]
        assert result["automated_log"] == "Completed with errors"

    @patch("urarovite.utils.sheets.rename_spreadsheet_title")
    @patch("urarovite.utils.sheets.get_sheet_values")
    def test_validate_failure_with_missing_error_messages(self, mock_get_values, mock_rename):
        """
        When failures lack explicit error messages, use default error message.
        """
        mock_get_values.return_value = {
            "success": True,
            "values": [["https://docs.google.com/spreadsheets/d/AAA/edit", "T1"]],
            "rows": 1,
            "cols": 2,
            "error": None,
        }
        mock_rename.return_value = {"success": False, "error": "Not authorized"}

        mock_service = Mock()

        result = self.validator.validate(
            sheets_service=mock_service,
            sheet_id="",
            mode="fix",
            template_sheet_url="https://docs.google.com/spreadsheets/d/template/edit",
            range="A1:B10",
        )

        assert result["issues_found"] == 1
        assert result["errors"] == ["Not authorized"]
        assert result["automated_log"] == "Completed with errors"

    @patch("urarovite.utils.sheets.get_sheet_values")
    def test_validate_failure_with_top_level_error(self, mock_get_values):
        """
        When operation fails with a top-level error and no per-row failures, report the message.
        """
        mock_get_values.return_value = {
            "success": False,
            "values": [],
            "rows": 0,
            "cols": 0,
            "error": "template_range_empty",
        }

        mock_service = Mock()

        result = self.validator.validate(
            sheets_service=mock_service,
            sheet_id="",
            mode="fix",
            template_sheet_url="https://docs.google.com/spreadsheets/d/template/edit",
            range="A1:B10",
        )

        assert result["issues_found"] == 0
        assert "template_range_empty" in result["errors"]
        assert result["automated_log"] == "Completed with errors"

    @patch("urarovite.utils.sheets.get_sheet_values")
    def test_validate_unexpected_exception(self, mock_get_values):
        """
        Ensure exceptions are caught and surfaced as an error with neutral log.
        """
        mock_get_values.side_effect = RuntimeError("Boom")

        mock_service = Mock()

        result = self.validator.validate(
            sheets_service=mock_service,
            sheet_id="",
            mode="fix",
            template_sheet_url="https://docs.google.com/spreadsheets/d/template/edit",
            range="A1:B10",
        )

        assert any("Unexpected error: Boom" in e for e in result["errors"]) 
        assert result["automated_log"] == "Completed with errors"

    @patch("urarovite.utils.sheets.rename_spreadsheet_title")
    @patch("urarovite.utils.sheets.get_sheet_values")
    def test_run_wrapper(self, mock_get_values, mock_rename):
        """
        Smoke test the run() helper to ensure it delegates to validator with fix mode.
        """
        mock_get_values.return_value = {
            "success": True,
            "values": [["https://docs.google.com/spreadsheets/d/AAA/edit", "T1"]],
            "rows": 1,
            "cols": 2,
            "error": None,
        }
        mock_rename.return_value = {"success": True}

        mock_service = Mock()

        result = run(
            sheets_service=mock_service,
            template_sheet_url="https://docs.google.com/spreadsheets/d/template/edit",
            range="A1:B2",
        )

        assert result["fixes_applied"] == 1
        assert result["errors"] == []
        assert result["automated_log"] == "Renamed successfully"


