"""
Drive migration tools — MyDrive → Shared Drive.

Implements a 15-step auditing and migration workflow that ensures full
visibility into source folders, files, and permissions before, during,
and after a migration to a Shared Drive.
"""

from gamcp.gam_runner import execute_gam


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _todrive_args(sheet_id: str, sheet_name: str) -> list[str]:
    """Standard todrive arguments used by every audit/log tool."""
    return [
        "todrive",
        "tdfileid", sheet_id,
        "tdsheet", sheet_name,
        "tdupdatesheet",
        "tdretaintitle",
    ]


# ---------------------------------------------------------------------------
# Registration
# ---------------------------------------------------------------------------

def register(mcp):

    # -----------------------------------------------------------------------
    # Step 1 — Configure todrive_noemail
    # -----------------------------------------------------------------------
    @mcp.tool()
    def configure_todrive_noemail() -> str:
        """
        Step 1 of the MyDrive → Shared Drive migration workflow.

        Sets the GAM configuration flag `todrive_noemail` to true so that
        emails are NOT sent to impersonated users when GAM writes output
        to Google Sheets via todrive.

        Run this ONCE before starting any audit steps.

        GAM command:
            gam config todrive_noemail true
        """
        return execute_gam(["config", "todrive_noemail", "true"])

    # -----------------------------------------------------------------------
    # Step 2 — Master file inventory
    # -----------------------------------------------------------------------
    @mcp.tool()
    def audit_file_inventory(
        user_email: str,
        folder_id: str,
        sheet_id: str,
        sheet_name: str = "file_audit",
    ) -> str:
        """
        Step 2 — Master file/folder inventory.

        Prints every file and folder under the source folder with full
        metadata and resolved file paths, then writes the results to the
        specified Google Sheet tab.

        Fields returned: id, name, mimeType, owners, parents, size,
        modifiedTime, createdTime, trashed.  `filepath` resolves the full
        path from root.  `excludetrashed` omits deleted content.

        NOTE: If the user has not yet created a Google Sheet, instruct them
        to create one named "Migration Audit" with tabs: file_audit,
        all_permissions, file_count, own, not_owner, external_owner,
        public_files, shortcuts, shared_drive_members, migration_log,
        post_migration_permissions.

        Args:
            user_email: The email of the user who owns the source folder.
            folder_id: The ID of the source folder to audit.
            sheet_id: The ID of the Google Sheet for output.
            sheet_name: The tab name to write to (default: "file_audit").

        GAM command:
            gam user <user_email> print filelist select <folder_id>
                fields "id,name,mimeType,owners,parents,size,modifiedTime,
                createdTime,trashed" filepath excludetrashed
                todrive tdfileid <sheet_id> tdsheet "<sheet_name>"
                tdupdatesheet tdretaintitle 
        """
        args = [
            "user", user_email,
            "print", "filelist",
            "select", folder_id,
            "fields", "id,name,mimeType,owners,parents,size,modifiedTime,createdTime,trashed",
            "filepath",
            "excludetrashed",
            
        ] + _todrive_args(sheet_id, sheet_name)

        result = execute_gam(args)
        return (
            f"File inventory written to Google Sheet ID: {sheet_id} "
            f"(tab: {sheet_name})\n\n{result}"
        )

    # -----------------------------------------------------------------------
    # Step 3 — File counts and sizes
    # -----------------------------------------------------------------------
    @mcp.tool()
    def audit_file_counts(
        user_email: str,
        folder_id: str,
        sheet_id: str,
        sheet_name: str = "file_count",
    ) -> str:
        """
        Step 3 — File count and storage summary.

        Produces a per-MIME-type breakdown of file counts and storage used
        inside the source folder.  Useful for capacity planning on the
        destination Shared Drive.

        Args:
            user_email: The email of the user who owns the source folder.
            folder_id: The ID of the source folder.
            sheet_id: The ID of the Google Sheet for output.
            sheet_name: The tab name (default: "file_count").

        GAM command:
            gam user <user_email> print filecounts query "'<folder_id>' in parents"
                showsize showmimetypesize excludetrashed
                todrive tdfileid <sheet_id> tdsheet "<sheet_name>"
                tdupdatesheet tdretaintitle 
        """
        args = [
            "user", user_email,
            "print", "filecounts",
            "query", f"'{folder_id}' in parents",
            "showsize", "showmimetypesize",
            "excludetrashed",
            
        ] + _todrive_args(sheet_id, sheet_name)

        result = execute_gam(args)
        return (
            f"File counts written to Google Sheet ID: {sheet_id} "
            f"(tab: {sheet_name})\n\n{result}"
        )

    # -----------------------------------------------------------------------
    # Step 4 — Files owned by the user
    # -----------------------------------------------------------------------
    @mcp.tool()
    def audit_owned_files(
        user_email: str,
        folder_id: str,
        sheet_id: str,
        sheet_name: str = "own",
    ) -> str:
        """
        Step 4 — Files owned by the migrating user.

        Only files owned by the user can be *moved* (not just copied) to a
        Shared Drive.  This audit isolates those items.

        Args:
            user_email: The email of the user who owns the source folder.
            folder_id: The ID of the source folder.
            sheet_id: The ID of the Google Sheet for output.
            sheet_name: The tab name (default: "own").

        GAM command:
            gam user <user_email> print filelist select <folder_id>
                showownedby me
                fields "id,name,mimeType,owners,modifiedTime"
                filepath excludetrashed
                todrive tdfileid <sheet_id> tdsheet "<sheet_name>"
                tdupdatesheet tdretaintitle 
        """
        args = [
            "user", user_email,
            "print", "filelist",
            "select", folder_id,
            "showownedby", "me",
            "fields", "id,name,mimeType,owners,modifiedTime",
            "filepath",
            "excludetrashed",
            
        ] + _todrive_args(sheet_id, sheet_name)

        result = execute_gam(args)
        return (
            f"Owned-file audit written to Google Sheet ID: {sheet_id} "
            f"(tab: {sheet_name})\n\n{result}"
        )

    # -----------------------------------------------------------------------
    # Step 5 — Files NOT owned by the user
    # -----------------------------------------------------------------------
    @mcp.tool()
    def audit_not_owned_files(
        user_email: str,
        folder_id: str,
        sheet_id: str,
        sheet_name: str = "not_owner",
    ) -> str:
        """
        Step 5 — Files owned by others.

        Files owned by other users inside this folder structure will NOT
        transfer with a standard move to a Shared Drive.  The host should
        inform the requesting user which folders/files are affected and
        that those items cannot be migrated.

        Args:
            user_email: The email of the user who owns the source folder.
            folder_id: The ID of the source folder.
            sheet_id: The ID of the Google Sheet for output.
            sheet_name: The tab name (default: "not_owner").

        GAM command:
            gam user <user_email> print filelist select <folder_id>
                showownedby others
                fields "id,name,mimeType,owners,sharingUser,modifiedTime"
                filepath excludetrashed
                todrive tdfileid <sheet_id> tdsheet "<sheet_name>"
                tdupdatesheet tdretaintitle 
        """
        args = [
            "user", user_email,
            "print", "filelist",
            "select", folder_id,
            "showownedby", "others",
            "fields", "id,name,mimeType,owners,sharingUser,modifiedTime",
            "filepath",
            "excludetrashed",
        ] + _todrive_args(sheet_id, sheet_name)

        result = execute_gam(args)
        return (
            f"Not-owned-file audit written to Google Sheet ID: {sheet_id} "
            f"(tab: {sheet_name})\n\n"
            "IMPORTANT: Files listed here are owned by other users and "
            "CANNOT be migrated to the Shared Drive via a standard move. "
            "Review and communicate this to the requesting user.\n\n"
            f"{result}"
        )

    # -----------------------------------------------------------------------
    # Step 6 — Full ACL (permissions) audit
    # -----------------------------------------------------------------------
    @mcp.tool()
    def audit_all_permissions(
        user_email: str,
        folder_id: str,
        sheet_id: str,
        sheet_name: str = "all_permissions",
    ) -> str:
        """
        Step 6 — Full Access Control List audit.

        Lists every permission entry (one row per ACL) for every file and
        folder under the source.  This sheet is the master reference used
        by the permission-reapplication steps (12–14) after migration.

        basicpermissions returns: allowFileDiscovery, deleted, domain,
        emailAddress, expirationTime, id, role, type.

        Args:
            user_email: The email of the user who owns the source folder.
            folder_id: The ID of the source folder.
            sheet_id: The ID of the Google Sheet for output.
            sheet_name: The tab name (default: "all_permissions").

        GAM command:
            gam user <user_email> print filelist select <folder_id>
                fields "id,name,mimeType,basicpermissions,owners"
                filepath excludetrashed oneitemperrow pmfilter
                todrive tdfileid <sheet_id> tdsheet "<sheet_name>"
                tdupdatesheet tdretaintitle 
        """
        args = [
            "user", user_email,
            "print", "filelist",
            "select", folder_id,
            "fields", "id,name,mimeType,basicpermissions,owners",
            "filepath",
            "excludetrashed",
            "oneitemperrow",
            "pmfilter",
            
        ] + _todrive_args(sheet_id, sheet_name)

        result = execute_gam(args)
        return (
            f"Full permissions audit written to Google Sheet ID: {sheet_id} "
            f"(tab: {sheet_name})\n\n{result}"
        )

    # -----------------------------------------------------------------------
    # Step 7 — External user permissions
    # -----------------------------------------------------------------------
    @mcp.tool()
    def audit_external_permissions(
        user_email: str,
        folder_id: str,
        sheet_id: str,
        domain: str,
        sheet_name: str = "external_owner",
    ) -> str:
        """
        Step 7 — Files shared with users outside your organisation.

        Flags files that have at least one permission entry for a user NOT
        in the specified domain.  These may require cleanup or
        re-evaluation before migrating to a Shared Drive with different
        sharing policies.

        Args:
            user_email: The email of the user who owns the source folder.
            folder_id: The ID of the source folder.
            sheet_id: The ID of the Google Sheet for output.
            domain: Your organisation's domain (e.g. "company.com").
            sheet_name: The tab name (default: "external_owner").

        GAM command:
            gam user <user_email> print filelist select <folder_id>
                fields "id,name,mimeType,basicpermissions,owners"
                filepath excludetrashed
                permissionmatch type user notdomainlist <domain> endmatch
                pmfilter oneitemperrow
                todrive tdfileid <sheet_id> tdsheet "<sheet_name>"
                tdupdatesheet tdretaintitle 
        """
        args = [
            "user", user_email,
            "print", "filelist",
            "select", folder_id,
            "fields", "id,name,mimeType,basicpermissions,owners",
            "filepath",
            "excludetrashed",
            "permissionmatch", "type", "user", "notdomainlist", domain, "endmatch",
            "pmfilter",
            "oneitemperrow",
            
        ] + _todrive_args(sheet_id, sheet_name)

        result = execute_gam(args)
        return (
            f"External permissions audit written to Google Sheet ID: {sheet_id} "
            f"(tab: {sheet_name})\n\n{result}"
        )

    # -----------------------------------------------------------------------
    # Step 8 — Public / "anyone with the link" files
    # -----------------------------------------------------------------------
    @mcp.tool()
    def audit_public_files(
        user_email: str,
        folder_id: str,
        sheet_id: str,
        sheet_name: str = "public_files",
    ) -> str:
        """
        Step 8 — Files accessible to "anyone with the link" or publicly.

        These are the highest-risk files from a security stand-point.
        Shared Drives can restrict this behaviour at the drive level, so
        you need to know what you are inheriting.

        Args:
            user_email: The email of the user who owns the source folder.
            folder_id: The ID of the source folder.
            sheet_id: The ID of the Google Sheet for output.
            sheet_name: The tab name (default: "public_files").

        GAM command:
            gam user <user_email> print filelist select <folder_id>
                fields "id,name,mimeType,basicpermissions,owners"
                filepath excludetrashed
                permissionmatch type anyone endmatch
                pmfilter oneitemperrow
                todrive tdfileid <sheet_id> tdsheet "<sheet_name>"
                tdupdatesheet tdretaintitle 
        """
        args = [
            "user", user_email,
            "print", "filelist",
            "select", folder_id,
            "fields", "id,name,mimeType,basicpermissions,owners",
            "filepath",
            "excludetrashed",
            "permissionmatch", "type", "anyone", "endmatch",
            "pmfilter",
            "oneitemperrow",
            
        ] + _todrive_args(sheet_id, sheet_name)

        result = execute_gam(args)
        return (
            f"Public-file audit written to Google Sheet ID: {sheet_id} "
            f"(tab: {sheet_name})\n\n{result}"
        )

    # -----------------------------------------------------------------------
    # Step 9 — Shortcuts
    # -----------------------------------------------------------------------
    @mcp.tool()
    def audit_shortcuts(
        user_email: str,
        folder_id: str,
        sheet_id: str,
        sheet_name: str = "shortcuts",
    ) -> str:
        """
        Step 9 — Identify Google Drive shortcuts.

        Shortcuts pointing to files outside the migration scope will break
        after the move since they reference the original file's location.
        shortcutDetails returns the targetId and targetMimeType so you can
        determine whether the target will also be in the Shared Drive
        post-migration.

        Args:
            user_email: The email of the user who owns the source folder.
            folder_id: The ID of the source folder.
            sheet_id: The ID of the Google Sheet for output.
            sheet_name: The tab name (default: "shortcuts").

        GAM command:
            gam user <user_email> print filelist select <folder_id>
                showmimetype gshortcut
                fields "id,name,shortcutDetails,parents,owners"
                filepath excludetrashed
                todrive tdfileid <sheet_id> tdsheet "<sheet_name>"
                tdupdatesheet tdretaintitle 
        """
        args = [
            "user", user_email,
            "print", "filelist",
            "select", folder_id,
            "showmimetype", "gshortcut",
            "fields", "id,name,shortcutDetails,parents,owners",
            "filepath",
            "excludetrashed",
            
        ] + _todrive_args(sheet_id, sheet_name)

        result = execute_gam(args)
        return (
            f"Shortcut audit written to Google Sheet ID: {sheet_id} "
            f"(tab: {sheet_name})\n\n{result}"
        )

    # -----------------------------------------------------------------------
    # Step 10 — Shared Drive members (destination planning)
    # -----------------------------------------------------------------------
    @mcp.tool()
    def audit_shared_drive_members(
        user_email: str,
        sheet_id: str,
        sheet_name: str = "shared_drive_members",
    ) -> str:
        """
        Step 10 — List existing Shared Drives and their members.

        Confirms the destination Shared Drive exists and who has what level
        of access.  The migrating user must be a Manager on the Shared
        Drive to move files into it.

        Args:
            user_email: The email of the admin user running the query.
            sheet_id: The ID of the Google Sheet for output.
            sheet_name: The tab name (default: "shared_drive_members").

        GAM command:
            gam user <user_email> print teamdriveacls
                fields "id,name,role,type,emailAddress"
                todrive tdfileid <sheet_id> tdsheet "<sheet_name>"
                tdupdatesheet tdretaintitle 
        """
        args = [
            "user", user_email,
            "print", "teamdriveacls",
            "fields", "id,name,role,type,emailAddress",
        ] + _todrive_args(sheet_id, sheet_name)

        result = execute_gam(args)
        return (
            f"Shared Drive members written to Google Sheet ID: {sheet_id} "
            f"(tab: {sheet_name})\n\n{result}"
        )

    # -----------------------------------------------------------------------
    # Step 11 — Execute migration move
    # -----------------------------------------------------------------------
    @mcp.tool()
    def execute_migration_move(
        user_email: str,
        folder_id: str,
        shared_drive_id: str,
        confirmed: bool = False,
    ) -> str:
        """
        Step 11 — Move the source folder tree to the Shared Drive.

        DESTRUCTIVE — requires confirmed=True to execute.

        Recursively moves the folder tree into the destination Shared Drive,
        merging duplicate folders and overwriting older duplicate files.
        Folder permissions are copied for both merged and newly created folders.

        NOTE: Run ALL audit steps (1–10) before executing this step.

        NOTE: CSV/todrive logging is not supported by `move drivefile`. To retain
        a record of the move, redirect stdout/stderr to a log file at the shell
        level, or run a `print filelist` audit step before and after migration.

        Args:
            user_email: The email of the folder owner (must be a Shared Drive
                        Manager/Organizer of the destination).
            folder_id: The ID of the source folder.
            shared_drive_id: The ID of the destination Shared Drive.
            confirmed: Must be True to execute. False returns a preview.

        GAM command:
            gam user <user_email> move drivefile <folder_id>
                teamdriveparentid <shared_drive_id>
                duplicatefiles overwriteolder
                duplicatefolders merge
                copymergedtopfolderpermissions true
                copymergedsubfolderpermissions true
                summary
        """
        args = [
            "user", user_email,
            "move", "drivefile", folder_id,
            "teamdriveparentid", shared_drive_id,
            "duplicatefiles", "overwriteolder",
            "duplicatefolders", "merge",
            "copymergedtopfolderpermissions", "true",
            "copymergedsubfolderpermissions", "true",
            "summary",
        ]

        if not confirmed:
            return (
                "PREVIEW (not executed — run with confirmed=True):\n"
                f"Command: gam {' '.join(args)}"
            )

        result = execute_gam(args)
        return f"Migration move completed.\n\n{result}"

    # -----------------------------------------------------------------------
    # Step 12 — Reapply user/group permissions
    # -----------------------------------------------------------------------
    @mcp.tool()
    def reapply_user_group_permissions(
        user_email: str,
        sheet_id: str,
        sheet_name: str = "all_permissions",
        confirmed: bool = False,
    ) -> str:
        """
        Step 12 — Reapply user and group permissions from the audit sheet.

        DESTRUCTIVE — requires confirmed=True to execute.

        Reads the all_permissions sheet and re-creates every user/group ACL
        on the corresponding file in the Shared Drive.  Processes only
        rows where permission.type is "user" or "group".

        INFO: Ownership cannot be transferred via ACL on a Shared Drive.
        In Shared Drives the drive itself is the owner — owner-role rows
        from the audit sheet will be silently ignored.

        Args:
            user_email: The admin email executing the command.
            sheet_id: The ID of the Google Sheet containing the audit.
            sheet_name: The tab containing ACL data (default: "all_permissions").
            confirmed: Must be True to execute. False returns a preview.

        GAM command:
            gam config csv_input_row_filter "permission.type:regex:user|group"
                redirect stdout ./reapply_user_group_perms.txt multiprocess
                redirect stderr stdout
                csv gsheet <user_email> <sheet_id> <sheet_name>
                gam user <user_email> create drivefileacl "~id"
                "~permission.type" "~permission.emailAddress"
                role "~permission.role" nodetails
        """
        args = [
            "config", "csv_input_row_filter", "permission.type:regex:user|group",
            "redirect", "stdout", "./reapply_user_group_perms.txt", "multiprocess",
            "redirect", "stderr", "stdout",
            "csv", "gsheet", user_email, sheet_id, sheet_name,
            "gam", "user", user_email, "create", "drivefileacl", "~id",
            "~permission.type", "~permission.emailAddress",
            "role", "~permission.role",
            "nodetails",
        ]

        if not confirmed:
            return (
                "PREVIEW (not executed — run with confirmed=True):\n"
                f"Command: gam {' '.join(args)}"
            )

        result = execute_gam(args)
        return f"User/group permissions reapplied.\n\n{result}"

    # -----------------------------------------------------------------------
    # Step 13 — Reapply domain permissions
    # -----------------------------------------------------------------------
    @mcp.tool()
    def reapply_domain_permissions(
        user_email: str,
        sheet_id: str,
        sheet_name: str = "all_permissions",
        confirmed: bool = False,
    ) -> str:
        """
        Step 13 — Reapply domain-wide permissions from the audit sheet.

        DESTRUCTIVE — requires confirmed=True to execute.

        Reads the all_permissions sheet and re-creates every domain ACL on
        the corresponding file in the Shared Drive.  Includes the
        allowFileDiscovery setting so domain-wide visibility is preserved.

        Args:
            user_email: The admin email executing the command.
            sheet_id: The ID of the Google Sheet containing the audit.
            sheet_name: The tab containing ACL data (default: "all_permissions").
            confirmed: Must be True to execute. False returns a preview.

        GAM command:
            gam config csv_input_row_filter "permission.type:regex:domain"
                redirect stdout ./reapply_domain_perms.txt multiprocess
                redirect stderr stdout
                csv gsheet <user_email> <sheet_id> <sheet_name>
                gam user <user_email> create drivefileacl "~id"
                "~permission.type" "~permission.domain"
                role "~permission.role"
                allowfilediscovery "~permission.allowFileDiscovery"
                nodetails
        """
        args = [
            "config", "csv_input_row_filter", "permission.type:regex:domain",
            "redirect", "stdout", "./reapply_domain_perms.txt", "multiprocess",
            "redirect", "stderr", "stdout",
            "csv", "gsheet", user_email, sheet_id, sheet_name,
            "gam", "user", user_email, "create", "drivefileacl", "~id",
            "~permission.type", "~permission.domain",
            "role", "~permission.role",
            "allowfilediscovery", "~permission.allowFileDiscovery",
            "nodetails",
        ]

        if not confirmed:
            return (
                "PREVIEW (not executed — run with confirmed=True):\n"
                f"Command: gam {' '.join(args)}"
            )

        result = execute_gam(args)
        return f"Domain permissions reapplied.\n\n{result}"

    # -----------------------------------------------------------------------
    # Step 14 — Reapply anyone permissions
    # -----------------------------------------------------------------------
    @mcp.tool()
    def reapply_anyone_permissions(
        user_email: str,
        sheet_id: str,
        sheet_name: str = "all_permissions",
        confirmed: bool = False,
    ) -> str:
        """
        Step 14 — Reapply "anyone" (public) permissions from the audit sheet.

        DESTRUCTIVE — requires confirmed=True to execute.

        If the audit captured any "anyone with the link" ACLs, this step
        reapplies them.  Consider whether public access is appropriate on
        the destination Shared Drive before confirming.

        Args:
            user_email: The admin email executing the command.
            sheet_id: The ID of the Google Sheet containing the audit.
            sheet_name: The tab containing ACL data (default: "all_permissions").
            confirmed: Must be True to execute. False returns a preview.

        GAM command:
            gam config csv_input_row_filter "permission.type:regex:anyone"
                redirect stdout ./reapply_anyone_perms.txt multiprocess
                redirect stderr stdout
                csv gsheet <user_email> <sheet_id> <sheet_name>
                gam user <user_email> create drivefileacl "~id"
                anyone role "~permission.role"
                allowfilediscovery "~permission.allowFileDiscovery"
                nodetails
        """
        args = [
            "config", "csv_input_row_filter", "permission.type:regex:anyone",
            "redirect", "stdout", "./reapply_anyone_perms.txt", "multiprocess",
            "redirect", "stderr", "stdout",
            "csv", "gsheet", user_email, sheet_id, sheet_name,
            "gam", "user", user_email, "create", "drivefileacl", "~id",
            "anyone",
            "role", "~permission.role",
            "allowfilediscovery", "~permission.allowFileDiscovery",
            "nodetails",
        ]

        if not confirmed:
            return (
                "PREVIEW (not executed — run with confirmed=True):\n"
                f"Command: gam {' '.join(args)}"
            )

        result = execute_gam(args)
        return f"Anyone permissions reapplied.\n\n{result}"

    # -----------------------------------------------------------------------
    # Step 15 — Post-migration permissions audit
    # -----------------------------------------------------------------------
    @mcp.tool()
    def audit_post_migration_permissions(
        user_email: str,
        shared_drive_id: str,
        sheet_id: str,
        sheet_name: str = "post_migration_permissions",
    ) -> str:
        """
        Step 15 — Post-migration permissions audit on the Shared Drive.

        After reapplying permissions (steps 12–14), run this final audit
        against the Shared Drive to confirm the ACLs match what was
        recorded pre-migration.  Compare this tab against the
        all_permissions tab to verify correctness.

        Args:
            user_email: The admin email executing the command.
            shared_drive_id: The ID of the destination Shared Drive.
            sheet_id: The ID of the Google Sheet for output.
            sheet_name: The tab name (default: "post_migration_permissions").

        GAM command:
            gam user <user_email> print filelist select <shared_drive_id>
                fields "id,name,mimeType,basicpermissions,owners"
                filepath excludetrashed oneitemperrow pmfilter
                todrive tdfileid <sheet_id> tdsheet "<sheet_name>"
                tdupdatesheet tdretaintitle
        """
        args = [
            "user", user_email,
            "print", "filelist",
            "select", shared_drive_id,
            "fields", "id,name,mimeType,basicpermissions,owners",
            "filepath",
            "excludetrashed",
            "oneitemperrow",
            "pmfilter",
        ] + _todrive_args(sheet_id, sheet_name)

        result = execute_gam(args)
        return (
            f"Post-migration permissions audit written to Google Sheet ID: "
            f"{sheet_id} (tab: {sheet_name})\n\n"
            "Compare this tab against the all_permissions tab to verify "
            "that permissions were correctly reapplied.\n\n"
            f"{result}"
        )
