     1→import Foundation
     2→
     3→// MARK: - Email Actions Extension
     4→
     5→extension GmailService {
     6→
     7→    // MARK: - Mark As Read
     8→
     9→    func markAsRead(emailId: String) async throws {
    10→        AppLogger.gmail("Gmail API: markAsRead - \(emailId)", level: .debug)
    11→
    12→        guard let token = await getValidToken() else {
    13→            AppLogger.gmail("Gmail API: markAsRead - não autenticado", level: .warning)
    14→            throw GmailError.notAuthenticated
    15→        }
    16→
    17→        try await withRetry(operation: "markAsRead") {
    18→            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/modify")!)
    19→            request.httpMethod = "POST"
    20→            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
    21→            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    22→
    23→            let body = ["removeLabelIds": ["UNREAD"]]
    24→            request.httpBody = try GmailService.encoder.encode(body)
    25→
    26→            let (_, response) = try await URLSession.shared.data(for: request)
    27→
    28→            guard let httpResponse = response as? HTTPURLResponse else {
    29→                throw GmailError.invalidResponse
    30→            }
    31→
    32→            switch httpResponse.statusCode {
    33→            case 200:
    34→                AppLogger.gmail("Gmail API: markAsRead sucesso - \(emailId)", level: .debug)
    35→                return
    36→            case 429:
    37→                AppLogger.gmail("Gmail API: markAsRead rate limited", level: .warning)
    38→                throw GmailError.rateLimited
    39→            default:
    40→                AppLogger.gmail("Gmail API: markAsRead falhou (\(httpResponse.statusCode))", level: .error)
    41→                throw GmailError.modifyFailed
    42→            }
    43→        }
    44→    }
    45→
    46→    // MARK: - Mark As Unread
    47→
    48→    func markAsUnread(emailId: String) async throws {
    49→        AppLogger.gmail("Gmail API: markAsUnread - \(emailId)", level: .debug)
    50→
    51→        guard let token = await getValidToken() else {
    52→            AppLogger.gmail("Gmail API: markAsUnread - não autenticado", level: .warning)
    53→            throw GmailError.notAuthenticated
    54→        }
    55→
    56→        try await withRetry(operation: "markAsUnread") {
    57→            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/modify")!)
    58→            request.httpMethod = "POST"
    59→            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
    60→            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    61→
    62→            let body = ["addLabelIds": ["UNREAD"]]
    63→            request.httpBody = try GmailService.encoder.encode(body)
    64→
    65→            let (_, response) = try await URLSession.shared.data(for: request)
    66→
    67→            guard let httpResponse = response as? HTTPURLResponse else {
    68→                throw GmailError.invalidResponse
    69→            }
    70→
    71→            switch httpResponse.statusCode {
    72→            case 200:
    73→                AppLogger.gmail("Gmail API: markAsUnread sucesso - \(emailId)", level: .debug)
    74→                return
    75→            case 429:
    76→                AppLogger.gmail("Gmail API: markAsUnread rate limited", level: .warning)
    77→                throw GmailError.rateLimited
    78→            default:
    79→                AppLogger.gmail("Gmail API: markAsUnread falhou (\(httpResponse.statusCode))", level: .error)
    80→                throw GmailError.modifyFailed
    81→            }
    82→        }
    83→    }
    84→
    85→    // MARK: - Toggle Star
    86→
    87→    func toggleStar(emailId: String, starred: Bool) async throws {
    88→        AppLogger.gmail("Gmail API: toggleStar - \(emailId) → \(starred ? "starred" : "unstarred")", level: .debug)
    89→
    90→        guard let token = await getValidToken() else {
    91→            AppLogger.gmail("Gmail API: toggleStar - não autenticado", level: .warning)
    92→            throw GmailError.notAuthenticated
    93→        }
    94→
    95→        try await withRetry(operation: "toggleStar") {
    96→            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/modify")!)
    97→            request.httpMethod = "POST"
    98→            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
    99→            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
   100→
   101→            let body: [String: [String]] = starred
   102→                ? ["addLabelIds": ["STARRED"]]
   103→                : ["removeLabelIds": ["STARRED"]]
   104→            request.httpBody = try GmailService.encoder.encode(body)
   105→
   106→            let (_, response) = try await URLSession.shared.data(for: request)
   107→
   108→            guard let httpResponse = response as? HTTPURLResponse else {
   109→                throw GmailError.invalidResponse
   110→            }
   111→
   112→            switch httpResponse.statusCode {
   113→            case 200:
   114→                AppLogger.gmail("Gmail API: toggleStar sucesso - \(emailId)", level: .debug)
   115→                return
   116→            case 429:
   117→                AppLogger.gmail("Gmail API: toggleStar rate limited", level: .warning)
   118→                throw GmailError.rateLimited
   119→            default:
   120→                AppLogger.gmail("Gmail API: toggleStar falhou (\(httpResponse.statusCode))", level: .error)
   121→                throw GmailError.modifyFailed
   122→            }
   123→        }
   124→    }
   125→
   126→    // MARK: - Archive Email
   127→
   128→    func archiveEmail(emailId: String) async throws {
   129→        AppLogger.gmail("Gmail API: archiveEmail - \(emailId)", level: .debug)
   130→
   131→        guard let token = await getValidToken() else {
   132→            AppLogger.gmail("Gmail API: archiveEmail - não autenticado", level: .warning)
   133→            throw GmailError.notAuthenticated
   134→        }
   135→
   136→        try await withRetry(operation: "archiveEmail") {
   137→            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/modify")!)
   138→            request.httpMethod = "POST"
   139→            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
   140→            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
   141→
   142→            let body = ["removeLabelIds": ["INBOX"]]
   143→            request.httpBody = try GmailService.encoder.encode(body)
   144→
   145→            let (_, response) = try await URLSession.shared.data(for: request)
   146→
   147→            guard let httpResponse = response as? HTTPURLResponse else {
   148→                throw GmailError.invalidResponse
   149→            }
   150→
   151→            switch httpResponse.statusCode {
   152→            case 200:
   153→                AppLogger.gmail("Gmail API: archiveEmail sucesso - \(emailId)", level: .info)
   154→                return
   155→            case 429:
   156→                AppLogger.gmail("Gmail API: archiveEmail rate limited", level: .warning)
   157→                throw GmailError.rateLimited
   158→            default:
   159→                AppLogger.gmail("Gmail API: archiveEmail falhou (\(httpResponse.statusCode))", level: .error)
   160→                throw GmailError.modifyFailed
   161→            }
   162→        }
   163→    }
   164→
   165→    // MARK: - Unarchive Email
   166→
   167→    func unarchiveEmail(emailId: String) async throws {
   168→        AppLogger.gmail("Gmail API: unarchiveEmail - \(emailId)", level: .debug)
   169→
   170→        guard let token = await getValidToken() else {
   171→            AppLogger.gmail("Gmail API: unarchiveEmail - não autenticado", level: .warning)
   172→            throw GmailError.notAuthenticated
   173→        }
   174→
   175→        try await withRetry(operation: "unarchiveEmail") {
   176→            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/modify")!)
   177→            request.httpMethod = "POST"
   178→            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
   179→            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
   180→
   181→            let body = ["addLabelIds": ["INBOX"]]
   182→            request.httpBody = try GmailService.encoder.encode(body)
   183→
   184→            let (_, response) = try await URLSession.shared.data(for: request)
   185→
   186→            guard let httpResponse = response as? HTTPURLResponse else {
   187→                throw GmailError.invalidResponse
   188→            }
   189→
   190→            switch httpResponse.statusCode {
   191→            case 200:
   192→                AppLogger.gmail("Gmail API: unarchiveEmail sucesso - \(emailId)", level: .info)
   193→                return
   194→            case 429:
   195→                AppLogger.gmail("Gmail API: unarchiveEmail rate limited", level: .warning)
   196→                throw GmailError.rateLimited
   197→            default:
   198→                AppLogger.gmail("Gmail API: unarchiveEmail falhou (\(httpResponse.statusCode))", level: .error)
   199→                throw GmailError.modifyFailed
   200→            }
   201→        }
   202→    }
   203→
   204→    // MARK: - Batch Modify Labels
   205→
   206→    func batchModifyLabels(emailIds: [String], addLabels: [String] = [], removeLabels: [String] = []) async throws {
   207→        AppLogger.gmail("Gmail API: batchModifyLabels - \(emailIds.count) emails, add: \(addLabels), remove: \(removeLabels)", level: .debug)
   208→
   209→        guard let authManager = authManager else {
   210→            AppLogger.gmail("Gmail API: batchModifyLabels - não autenticado", level: .warning)
   211→            throw GmailError.notAuthenticated
   212→        }
   213→
   214→        guard !emailIds.isEmpty else {
   215→            AppLogger.gmail("Gmail API: batchModifyLabels - lista vazia, ignorando", level: .debug)
   216→            return
   217→        }
   218→
   219→        var hasTriedRefresh = false
   220→
   221→        while true {
   222→            guard let token = await authManager.getValidAccessToken() else {
   223→                throw GmailError.notAuthenticated
   224→            }
   225→
   226→            var request = URLRequest(url: URL(string: "\(baseURL)/messages/batchModify")!)
   227→            request.httpMethod = "POST"
   228→            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
   229→            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
   230→
   231→            var body: [String: Any] = ["ids": emailIds]
   232→            if !addLabels.isEmpty {
   233→                body["addLabelIds"] = addLabels
   234→            }
   235→            if !removeLabels.isEmpty {
   236→                body["removeLabelIds"] = removeLabels
   237→            }
   238→            request.httpBody = try JSONSerialization.data(withJSONObject: body)
   239→
   240→            let (_, response) = try await URLSession.shared.data(for: request)
   241→
   242→            guard let httpResponse = response as? HTTPURLResponse else {
   243→                throw GmailError.invalidResponse
   244→            }
   245→
   246→            switch httpResponse.statusCode {
   247→            case 200, 204:
   248→                AppLogger.gmail("Gmail API: batchModifyLabels sucesso - \(emailIds.count) emails modificados", level: .info)
   249→                return
   250→            case 401:
   251→                if !hasTriedRefresh {
   252→                    AppLogger.gmail("Gmail API: Token expirado durante batch, atualizando...", level: .debug)
   253→                    hasTriedRefresh = true
   254→                    await authManager.refreshAccessToken()
   255→                    continue
   256→                }
   257→                AppLogger.gmail("Gmail API: batchModifyLabels - autenticação falhou após refresh", level: .error)
   258→                throw GmailError.notAuthenticated
   259→            case 429:
   260→                AppLogger.gmail("Gmail API: batchModifyLabels rate limited", level: .warning)
   261→                throw GmailError.rateLimited
   262→            default:
   263→                AppLogger.gmail("Gmail API: batchModifyLabels falhou (\(httpResponse.statusCode))", level: .error)
   264→                throw GmailError.modifyFailed
   265→            }
   266→        }
   267→    }
   268→
   269→    // MARK: - Trash Email
   270→
   271→    func trashEmail(emailId: String) async throws {
   272→        AppLogger.gmail("Gmail API: trashEmail - \(emailId)", level: .debug)
   273→
   274→        guard let authManager = authManager else {
   275→            AppLogger.gmail("Gmail API: trashEmail - não autenticado", level: .warning)
   276→            throw GmailError.notAuthenticated
   277→        }
   278→
   279→        var hasTriedRefresh = false
   280→
   281→        while true {
   282→            guard let token = await authManager.getValidAccessToken() else {
   283→                throw GmailError.notAuthenticated
   284→            }
   285→
   286→            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/trash")!)
   287→            request.httpMethod = "POST"
   288→            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
   289→
   290→            let (_, response) = try await URLSession.shared.data(for: request)
   291→
   292→            guard let httpResponse = response as? HTTPURLResponse else {
   293→                throw GmailError.invalidResponse
   294→            }
   295→
   296→            switch httpResponse.statusCode {
   297→            case 200:
   298→                AppLogger.gmail("Gmail API: trashEmail sucesso - \(emailId)", level: .info)
   299→                return
   300→            case 401:
   301→                if !hasTriedRefresh {
   302→                    AppLogger.gmail("Gmail API: Token expirado durante trash, atualizando...", level: .debug)
   303→                    hasTriedRefresh = true
   304→                    await authManager.refreshAccessToken()
   305→                    continue
   306→                }
   307→                AppLogger.gmail("Gmail API: trashEmail - autenticação falhou após refresh", level: .error)
   308→                throw GmailError.notAuthenticated
   309→            case 429:
   310→                AppLogger.gmail("Gmail API: trashEmail rate limited", level: .warning)
   311→                throw GmailError.rateLimited
   312→            case 404:
   313→                AppLogger.gmail("Gmail API: trashEmail - email não encontrado", level: .warning)
   314→                throw GmailError.deleteFailed("Email not found")
   315→            default:
   316→                AppLogger.gmail("Gmail API: trashEmail falhou (\(httpResponse.statusCode))", level: .error)
   317→                throw GmailError.deleteFailed("Server error: \(httpResponse.statusCode)")
   318→            }
   319→        }
   320→    }
   321→
   322→    // MARK: - Delete Permanently
   323→
   324→    func deleteEmailPermanently(emailId: String) async throws {
   325→        AppLogger.gmail("Gmail API: deleteEmailPermanently - \(emailId)", level: .debug)
   326→
   327→        guard let token = await getValidToken() else {
   328→            AppLogger.gmail("Gmail API: deleteEmailPermanently - não autenticado", level: .warning)
   329→            throw GmailError.notAuthenticated
   330→        }
   331→
   332→        try await withRetry(operation: "deleteEmail") {
   333→            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)")!)
   334→            request.httpMethod = "DELETE"
   335→            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
   336→
   337→            let (_, response) = try await URLSession.shared.data(for: request)
   338→
   339→            guard let httpResponse = response as? HTTPURLResponse else {
   340→                throw GmailError.invalidResponse
   341→            }
   342→
   343→            switch httpResponse.statusCode {
   344→            case 200, 204:
   345→                AppLogger.gmail("Gmail API: deleteEmailPermanently sucesso - \(emailId)", level: .info)
   346→                return
   347→            case 429:
   348→                AppLogger.gmail("Gmail API: deleteEmailPermanently rate limited", level: .warning)
   349→                throw GmailError.rateLimited
   350→            case 404:
   351→                AppLogger.gmail("Gmail API: deleteEmailPermanently - email não encontrado", level: .warning)
   352→                throw GmailError.deleteFailed("Email not found")
   353→            default:
   354→                AppLogger.gmail("Gmail API: deleteEmailPermanently falhou (\(httpResponse.statusCode))", level: .error)
   355→                throw GmailError.deleteFailed("Server error: \(httpResponse.statusCode)")
   356→            }
   357→        }
   358→    }
   359→}
   360→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import Foundation

// MARK: - Email Actions Extension

extension GmailService {

    // MARK: - Mark As Read

    func markAsRead(emailId: String) async throws {
        AppLogger.gmail("Gmail API: markAsRead - \(emailId)", level: .debug)

        guard let token = await getValidToken() else {
            AppLogger.gmail("Gmail API: markAsRead - não autenticado", level: .warning)
            throw GmailError.notAuthenticated
        }

        try await withRetry(operation: "markAsRead") {
            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/modify")!)
            request.httpMethod = "POST"
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")

            let body = ["removeLabelIds": ["UNREAD"]]
            request.httpBody = try GmailService.encoder.encode(body)

            let (_, response) = try await URLSession.shared.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse else {
                throw GmailError.invalidResponse
            }

            switch httpResponse.statusCode {
            case 200:
                AppLogger.gmail("Gmail API: markAsRead sucesso - \(emailId)", level: .debug)
                return
            case 429:
                AppLogger.gmail("Gmail API: markAsRead rate limited", level: .warning)
                throw GmailError.rateLimited
            default:
                AppLogger.gmail("Gmail API: markAsRead falhou (\(httpResponse.statusCode))", level: .error)
                throw GmailError.modifyFailed
            }
        }
    }

    // MARK: - Mark As Unread

    func markAsUnread(emailId: String) async throws {
        AppLogger.gmail("Gmail API: markAsUnread - \(emailId)", level: .debug)

        guard let token = await getValidToken() else {
            AppLogger.gmail("Gmail API: markAsUnread - não autenticado", level: .warning)
            throw GmailError.notAuthenticated
        }

        try await withRetry(operation: "markAsUnread") {
            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/modify")!)
            request.httpMethod = "POST"
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")

            let body = ["addLabelIds": ["UNREAD"]]
            request.httpBody = try GmailService.encoder.encode(body)

            let (_, response) = try await URLSession.shared.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse else {
                throw GmailError.invalidResponse
            }

            switch httpResponse.statusCode {
            case 200:
                AppLogger.gmail("Gmail API: markAsUnread sucesso - \(emailId)", level: .debug)
                return
            case 429:
                AppLogger.gmail("Gmail API: markAsUnread rate limited", level: .warning)
                throw GmailError.rateLimited
            default:
                AppLogger.gmail("Gmail API: markAsUnread falhou (\(httpResponse.statusCode))", level: .error)
                throw GmailError.modifyFailed
            }
        }
    }

    // MARK: - Toggle Star

    func toggleStar(emailId: String, starred: Bool) async throws {
        AppLogger.gmail("Gmail API: toggleStar - \(emailId) → \(starred ? "starred" : "unstarred")", level: .debug)

        guard let token = await getValidToken() else {
            AppLogger.gmail("Gmail API: toggleStar - não autenticado", level: .warning)
            throw GmailError.notAuthenticated
        }

        try await withRetry(operation: "toggleStar") {
            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/modify")!)
            request.httpMethod = "POST"
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")

            let body: [String: [String]] = starred
                ? ["addLabelIds": ["STARRED"]]
                : ["removeLabelIds": ["STARRED"]]
            request.httpBody = try GmailService.encoder.encode(body)

            let (_, response) = try await URLSession.shared.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse else {
                throw GmailError.invalidResponse
            }

            switch httpResponse.statusCode {
            case 200:
                AppLogger.gmail("Gmail API: toggleStar sucesso - \(emailId)", level: .debug)
                return
            case 429:
                AppLogger.gmail("Gmail API: toggleStar rate limited", level: .warning)
                throw GmailError.rateLimited
            default:
                AppLogger.gmail("Gmail API: toggleStar falhou (\(httpResponse.statusCode))", level: .error)
                throw GmailError.modifyFailed
            }
        }
    }

    // MARK: - Archive Email

    func archiveEmail(emailId: String) async throws {
        AppLogger.gmail("Gmail API: archiveEmail - \(emailId)", level: .debug)

        guard let token = await getValidToken() else {
            AppLogger.gmail("Gmail API: archiveEmail - não autenticado", level: .warning)
            throw GmailError.notAuthenticated
        }

        try await withRetry(operation: "archiveEmail") {
            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/modify")!)
            request.httpMethod = "POST"
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")

            let body = ["removeLabelIds": ["INBOX"]]
            request.httpBody = try GmailService.encoder.encode(body)

            let (_, response) = try await URLSession.shared.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse else {
                throw GmailError.invalidResponse
            }

            switch httpResponse.statusCode {
            case 200:
                AppLogger.gmail("Gmail API: archiveEmail sucesso - \(emailId)", level: .info)
                return
            case 429:
                AppLogger.gmail("Gmail API: archiveEmail rate limited", level: .warning)
                throw GmailError.rateLimited
            default:
                AppLogger.gmail("Gmail API: archiveEmail falhou (\(httpResponse.statusCode))", level: .error)
                throw GmailError.modifyFailed
            }
        }
    }

    // MARK: - Unarchive Email

    func unarchiveEmail(emailId: String) async throws {
        AppLogger.gmail("Gmail API: unarchiveEmail - \(emailId)", level: .debug)

        guard let token = await getValidToken() else {
            AppLogger.gmail("Gmail API: unarchiveEmail - não autenticado", level: .warning)
            throw GmailError.notAuthenticated
        }

        try await withRetry(operation: "unarchiveEmail") {
            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/modify")!)
            request.httpMethod = "POST"
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")

            let body = ["addLabelIds": ["INBOX"]]
            request.httpBody = try GmailService.encoder.encode(body)

            let (_, response) = try await URLSession.shared.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse else {
                throw GmailError.invalidResponse
            }

            switch httpResponse.statusCode {
            case 200:
                AppLogger.gmail("Gmail API: unarchiveEmail sucesso - \(emailId)", level: .info)
                return
            case 429:
                AppLogger.gmail("Gmail API: unarchiveEmail rate limited", level: .warning)
                throw GmailError.rateLimited
            default:
                AppLogger.gmail("Gmail API: unarchiveEmail falhou (\(httpResponse.statusCode))", level: .error)
                throw GmailError.modifyFailed
            }
        }
    }

    // MARK: - Batch Modify Labels

    func batchModifyLabels(emailIds: [String], addLabels: [String] = [], removeLabels: [String] = []) async throws {
        AppLogger.gmail("Gmail API: batchModifyLabels - \(emailIds.count) emails, add: \(addLabels), remove: \(removeLabels)", level: .debug)

        guard let authManager = authManager else {
            AppLogger.gmail("Gmail API: batchModifyLabels - não autenticado", level: .warning)
            throw GmailError.notAuthenticated
        }

        guard !emailIds.isEmpty else {
            AppLogger.gmail("Gmail API: batchModifyLabels - lista vazia, ignorando", level: .debug)
            return
        }

        var hasTriedRefresh = false

        while true {
            guard let token = await authManager.getValidAccessToken() else {
                throw GmailError.notAuthenticated
            }

            var request = URLRequest(url: URL(string: "\(baseURL)/messages/batchModify")!)
            request.httpMethod = "POST"
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")

            var body: [String: Any] = ["ids": emailIds]
            if !addLabels.isEmpty {
                body["addLabelIds"] = addLabels
            }
            if !removeLabels.isEmpty {
                body["removeLabelIds"] = removeLabels
            }
            request.httpBody = try JSONSerialization.data(withJSONObject: body)

            let (_, response) = try await URLSession.shared.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse else {
                throw GmailError.invalidResponse
            }

            switch httpResponse.statusCode {
            case 200, 204:
                AppLogger.gmail("Gmail API: batchModifyLabels sucesso - \(emailIds.count) emails modificados", level: .info)
                return
            case 401:
                if !hasTriedRefresh {
                    AppLogger.gmail("Gmail API: Token expirado durante batch, atualizando...", level: .debug)
                    hasTriedRefresh = true
                    await authManager.refreshAccessToken()
                    continue
                }
                AppLogger.gmail("Gmail API: batchModifyLabels - autenticação falhou após refresh", level: .error)
                throw GmailError.notAuthenticated
            case 429:
                AppLogger.gmail("Gmail API: batchModifyLabels rate limited", level: .warning)
                throw GmailError.rateLimited
            default:
                AppLogger.gmail("Gmail API: batchModifyLabels falhou (\(httpResponse.statusCode))", level: .error)
                throw GmailError.modifyFailed
            }
        }
    }

    // MARK: - Trash Email

    func trashEmail(emailId: String) async throws {
        AppLogger.gmail("Gmail API: trashEmail - \(emailId)", level: .debug)

        guard let authManager = authManager else {
            AppLogger.gmail("Gmail API: trashEmail - não autenticado", level: .warning)
            throw GmailError.notAuthenticated
        }

        var hasTriedRefresh = false

        while true {
            guard let token = await authManager.getValidAccessToken() else {
                throw GmailError.notAuthenticated
            }

            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)/trash")!)
            request.httpMethod = "POST"
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")

            let (_, response) = try await URLSession.shared.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse else {
                throw GmailError.invalidResponse
            }

            switch httpResponse.statusCode {
            case 200:
                AppLogger.gmail("Gmail API: trashEmail sucesso - \(emailId)", level: .info)
                return
            case 401:
                if !hasTriedRefresh {
                    AppLogger.gmail("Gmail API: Token expirado durante trash, atualizando...", level: .debug)
                    hasTriedRefresh = true
                    await authManager.refreshAccessToken()
                    continue
                }
                AppLogger.gmail("Gmail API: trashEmail - autenticação falhou após refresh", level: .error)
                throw GmailError.notAuthenticated
            case 429:
                AppLogger.gmail("Gmail API: trashEmail rate limited", level: .warning)
                throw GmailError.rateLimited
            case 404:
                AppLogger.gmail("Gmail API: trashEmail - email não encontrado", level: .warning)
                throw GmailError.deleteFailed("Email not found")
            default:
                AppLogger.gmail("Gmail API: trashEmail falhou (\(httpResponse.statusCode))", level: .error)
                throw GmailError.deleteFailed("Server error: \(httpResponse.statusCode)")
            }
        }
    }

    // MARK: - Delete Permanently

    func deleteEmailPermanently(emailId: String) async throws {
        AppLogger.gmail("Gmail API: deleteEmailPermanently - \(emailId)", level: .debug)

        guard let token = await getValidToken() else {
            AppLogger.gmail("Gmail API: deleteEmailPermanently - não autenticado", level: .warning)
            throw GmailError.notAuthenticated
        }

        try await withRetry(operation: "deleteEmail") {
            var request = URLRequest(url: URL(string: "\(baseURL)/messages/\(emailId)")!)
            request.httpMethod = "DELETE"
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")

            let (_, response) = try await URLSession.shared.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse else {
                throw GmailError.invalidResponse
            }

            switch httpResponse.statusCode {
            case 200, 204:
                AppLogger.gmail("Gmail API: deleteEmailPermanently sucesso - \(emailId)", level: .info)
                return
            case 429:
                AppLogger.gmail("Gmail API: deleteEmailPermanently rate limited", level: .warning)
                throw GmailError.rateLimited
            case 404:
                AppLogger.gmail("Gmail API: deleteEmailPermanently - email não encontrado", level: .warning)
                throw GmailError.deleteFailed("Email not found")
            default:
                AppLogger.gmail("Gmail API: deleteEmailPermanently falhou (\(httpResponse.statusCode))", level: .error)
                throw GmailError.deleteFailed("Server error: \(httpResponse.statusCode)")
            }
        }
    }
}


Now let me check the Smart Folders and cleanup views:


     1→import Foundation
     2→
     3→// MARK: - EmailStore Filtering Extension
     4→
     5→extension EmailStore {
     6→
     7→    // MARK: - Filtered Emails
     8→
     9→    var filteredEmails: [Email] {
    10→        emails.filter { email in
    11→            let matchesSearch = searchQuery.isEmpty ||
    12→                email.subject.localizedCaseInsensitiveContains(searchQuery) ||
    13→                email.from.localizedCaseInsensitiveContains(searchQuery) ||
    14→                email.snippet.localizedCaseInsensitiveContains(searchQuery)
    15→
    16→            let matchesCategory = selectedCategory == nil ||
    17→                email.analysis?.category == selectedCategory
    18→
    19→            let matchesPriority = selectedPriority == nil ||
    20→                email.analysis?.priority == selectedPriority
    21→
    22→            let matchesUnread = !showUnreadOnly || !email.isRead
    23→
    24→            let matchesDate = matchesDateFilter(email.date)
    25→
    26→            return matchesSearch && matchesCategory && matchesPriority && matchesUnread && matchesDate
    27→        }
    28→        .sorted { $0.date > $1.date }
    29→    }
    30→
    31→    // MARK: - Date Filter Helper
    32→
    33→    private func matchesDateFilter(_ emailDate: Date) -> Bool {
    34→        let calendar = Calendar.current
    35→        let now = Date()
    36→
    37→        switch selectedDateFilter {
    38→        case .all:
    39→            return true
    40→        case .today:
    41→            let matches = calendar.isDateInToday(emailDate)
    42→            return matches
    43→        case .yesterday:
    44→            let matches = calendar.isDateInYesterday(emailDate)
    45→            return matches
    46→        case .last7days:
    47→            guard let sevenDaysAgo = calendar.date(byAdding: .day, value: -7, to: now) else { return true }
    48→            return emailDate >= calendar.startOfDay(for: sevenDaysAgo)
    49→        case .last30days:
    50→            guard let thirtyDaysAgo = calendar.date(byAdding: .day, value: -30, to: now) else { return true }
    51→            return emailDate >= calendar.startOfDay(for: thirtyDaysAgo)
    52→        case .custom:
    53→            let startOfCustomStart = calendar.startOfDay(for: customDateStart)
    54→            let endOfCustomEnd = calendar.date(byAdding: .day, value: 1, to: calendar.startOfDay(for: customDateEnd)) ?? customDateEnd
    55→            return emailDate >= startOfCustomStart && emailDate < endOfCustomEnd
    56→        }
    57→    }
    58→
    59→    // MARK: - Smart Folders
    60→
    61→    /// Emails requiring user action (high priority, has action items, unread)
    62→    var requiresActionEmails: [Email] {
    63→        emails.filter { email in
    64→            guard let analysis = email.analysis else { return false }
    65→            return (analysis.priority == .high || analysis.priority == .critical) &&
    66→                   analysis.hasActionItems &&
    67→                   !email.isRead
    68→        }
    69→        .sorted { $0.date > $1.date }
    70→    }
    71→
    72→    /// Emails AI recommends as safe to delete (importanceScore < 30, not suspicious)
    73→    var safeToDeleteEmails: [Email] {
    74→        emails.filter { email in
    75→            guard let analysis = email.analysis else { return false }
    76→            return analysis.deleteRecommendation == .safeToDelete
    77→        }
    78→        .sorted { ($0.analysis?.importanceScore ?? 100) < ($1.analysis?.importanceScore ?? 100) }
    79→    }
    80→
    81→    /// Emails that need review before deletion (importanceScore 30-60)
    82→    var reviewEmails: [Email] {
    83→        emails.filter { email in
    84→            guard let analysis = email.analysis else { return false }
    85→            return analysis.deleteRecommendation == .review
    86→        }
    87→        .sorted { $0.date > $1.date }
    88→    }
    89→
    90→    /// Suspicious emails (phishing, spam)
    91→    var suspiciousEmails: [Email] {
    92→        emails.filter { email in
    93→            guard let analysis = email.analysis else { return false }
    94→            return analysis.deleteRecommendation == .suspicious
    95→        }
    96→        .sorted { $0.date > $1.date }
    97→    }
    98→
    99→    /// Old unread emails (> 7 days, unread)
   100→    var oldUnreadEmails: [Email] {
   101→        let sevenDaysAgo = Calendar.current.date(byAdding: .day, value: -7, to: Date()) ?? Date()
   102→        return emails.filter { email in
   103→            !email.isRead && email.date < sevenDaysAgo
   104→        }
   105→        .sorted { $0.date < $1.date }
   106→    }
   107→
   108→    /// Important emails to keep (importanceScore >= 60)
   109→    var importantEmails: [Email] {
   110→        emails.filter { email in
   111→            guard let analysis = email.analysis else { return false }
   112→            return analysis.deleteRecommendation == .keep
   113→        }
   114→        .sorted { ($0.analysis?.importanceScore ?? 0) > ($1.analysis?.importanceScore ?? 0) }
   115→    }
   116→
   117→    // MARK: - Cleanup Statistics
   118→
   119→    var cleanupStats: CleanupStats {
   120→        CleanupStats(
   121→            safeToDeleteCount: safeToDeleteEmails.count,
   122→            reviewCount: reviewEmails.count,
   123→            suspiciousCount: suspiciousEmails.count,
   124→            oldUnreadCount: oldUnreadEmails.count,
   125→            requiresActionCount: requiresActionEmails.count,
   126→            importantCount: importantEmails.count
   127→        )
   128→    }
   129→
   130→    /// Group safe-to-delete by category for review UI
   131→    var safeToDeleteByCategory: [EmailAnalysis.Category: [Email]] {
   132→        Dictionary(grouping: safeToDeleteEmails) { email in
   133→            email.analysis?.category ?? .other
   134→        }
   135→    }
   136→}
   137→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import Foundation

// MARK: - EmailStore Filtering Extension

extension EmailStore {

    // MARK: - Filtered Emails

    var filteredEmails: [Email] {
        emails.filter { email in
            let matchesSearch = searchQuery.isEmpty ||
                email.subject.localizedCaseInsensitiveContains(searchQuery) ||
                email.from.localizedCaseInsensitiveContains(searchQuery) ||
                email.snippet.localizedCaseInsensitiveContains(searchQuery)

            let matchesCategory = selectedCategory == nil ||
                email.analysis?.category == selectedCategory

            let matchesPriority = selectedPriority == nil ||
                email.analysis?.priority == selectedPriority

            let matchesUnread = !showUnreadOnly || !email.isRead

            let matchesDate = matchesDateFilter(email.date)

            return matchesSearch && matchesCategory && matchesPriority && matchesUnread && matchesDate
        }
        .sorted { $0.date > $1.date }
    }

    // MARK: - Date Filter Helper

    private func matchesDateFilter(_ emailDate: Date) -> Bool {
        let calendar = Calendar.current
        let now = Date()

        switch selectedDateFilter {
        case .all:
            return true
        case .today:
            let matches = calendar.isDateInToday(emailDate)
            return matches
        case .yesterday:
            let matches = calendar.isDateInYesterday(emailDate)
            return matches
        case .last7days:
            guard let sevenDaysAgo = calendar.date(byAdding: .day, value: -7, to: now) else { return true }
            return emailDate >= calendar.startOfDay(for: sevenDaysAgo)
        case .last30days:
            guard let thirtyDaysAgo = calendar.date(byAdding: .day, value: -30, to: now) else { return true }
            return emailDate >= calendar.startOfDay(for: thirtyDaysAgo)
        case .custom:
            let startOfCustomStart = calendar.startOfDay(for: customDateStart)
            let endOfCustomEnd = calendar.date(byAdding: .day, value: 1, to: calendar.startOfDay(for: customDateEnd)) ?? customDateEnd
            return emailDate >= startOfCustomStart && emailDate < endOfCustomEnd
        }
    }

    // MARK: - Smart Folders

    /// Emails requiring user action (high priority, has action items, unread)
    var requiresActionEmails: [Email] {
        emails.filter { email in
            guard let analysis = email.analysis else { return false }
            return (analysis.priority == .high || analysis.priority == .critical) &&
                   analysis.hasActionItems &&
                   !email.isRead
        }
        .sorted { $0.date > $1.date }
    }

    /// Emails AI recommends as safe to delete (importanceScore < 30, not suspicious)
    var safeToDeleteEmails: [Email] {
        emails.filter { email in
            guard let analysis = email.analysis else { return false }
            return analysis.deleteRecommendation == .safeToDelete
        }
        .sorted { ($0.analysis?.importanceScore ?? 100) < ($1.analysis?.importanceScore ?? 100) }
    }

    /// Emails that need review before deletion (importanceScore 30-60)
    var reviewEmails: [Email] {
        emails.filter { email in
            guard let analysis = email.analysis else { return false }
            return analysis.deleteRecommendation == .review
        }
        .sorted { $0.date > $1.date }
    }

    /// Suspicious emails (phishing, spam)
    var suspiciousEmails: [Email] {
        emails.filter { email in
            guard let analysis = email.analysis else { return false }
            return analysis.deleteRecommendation == .suspicious
        }
        .sorted { $0.date > $1.date }
    }

    /// Old unread emails (> 7 days, unread)
    var oldUnreadEmails: [Email] {
        let sevenDaysAgo = Calendar.current.date(byAdding: .day, value: -7, to: Date()) ?? Date()
        return emails.filter { email in
            !email.isRead && email.date < sevenDaysAgo
        }
        .sorted { $0.date < $1.date }
    }

    /// Important emails to keep (importanceScore >= 60)
    var importantEmails: [Email] {
        emails.filter { email in
            guard let analysis = email.analysis else { return false }
            return analysis.deleteRecommendation == .keep
        }
        .sorted { ($0.analysis?.importanceScore ?? 0) > ($1.analysis?.importanceScore ?? 0) }
    }

    // MARK: - Cleanup Statistics

    var cleanupStats: CleanupStats {
        CleanupStats(
            safeToDeleteCount: safeToDeleteEmails.count,
            reviewCount: reviewEmails.count,
            suspiciousCount: suspiciousEmails.count,
            oldUnreadCount: oldUnreadEmails.count,
            requiresActionCount: requiresActionEmails.count,
            importantCount: importantEmails.count
        )
    }

    /// Group safe-to-delete by category for review UI
    var safeToDeleteByCategory: [EmailAnalysis.Category: [Email]] {
        Dictionary(grouping: safeToDeleteEmails) { email in
            email.analysis?.category ?? .other
        }
    }
}


     1→import SwiftUI
     2→
     3→// MARK: - Smart Folders View
     4→// Components extracted to: SmartFolderComponents.swift, SmartFolderDetailView.swift
     5→
     6→struct SmartFoldersView: View {
     7→    @EnvironmentObject var emailStore: EmailStore
     8→    @State private var selectedFolder: SmartFolder?
     9→
    10→    var body: some View {
    11→        NavigationStack {
    12→            List {
    13→                // Cleanup Summary Card
    14→                if emailStore.stats.analyzedCount > 0 {
    15→                    CleanupSummaryCard(stats: emailStore.cleanupStats)
    16→                        .listRowInsets(EdgeInsets())
    17→                        .listRowBackground(Color.clear)
    18→                }
    19→
    20→                // Action Required Section
    21→                Section {
    22→                    SmartFolderRow(
    23→                        folder: .requiresAction,
    24→                        count: emailStore.requiresActionEmails.count
    25→                    )
    26→                    .onTapGesture {
    27→                        selectedFolder = .requiresAction
    28→                    }
    29→                } header: {
    30→                    Text("Action Required")
    31→                }
    32→
    33→                // Cleanup Section
    34→                Section {
    35→                    SmartFolderRow(
    36→                        folder: .safeToDelete,
    37→                        count: emailStore.safeToDeleteEmails.count
    38→                    )
    39→                    .onTapGesture {
    40→                        selectedFolder = .safeToDelete
    41→                    }
    42→
    43→                    SmartFolderRow(
    44→                        folder: .suspicious,
    45→                        count: emailStore.suspiciousEmails.count
    46→                    )
    47→                    .onTapGesture {
    48→                        selectedFolder = .suspicious
    49→                    }
    50→
    51→                    SmartFolderRow(
    52→                        folder: .review,
    53→                        count: emailStore.reviewEmails.count
    54→                    )
    55→                    .onTapGesture {
    56→                        selectedFolder = .review
    57→                    }
    58→                } header: {
    59→                    Text("Cleanup Candidates")
    60→                } footer: {
    61→                    Text("AI-analyzed emails ready for cleanup review")
    62→                }
    63→
    64→                // Keep Section
    65→                Section {
    66→                    SmartFolderRow(
    67→                        folder: .important,
    68→                        count: emailStore.importantEmails.count
    69→                    )
    70→                    .onTapGesture {
    71→                        selectedFolder = .important
    72→                    }
    73→
    74→                    SmartFolderRow(
    75→                        folder: .oldUnread,
    76→                        count: emailStore.oldUnreadEmails.count
    77→                    )
    78→                    .onTapGesture {
    79→                        selectedFolder = .oldUnread
    80→                    }
    81→                } header: {
    82→                    Text("Review")
    83→                }
    84→
    85→                // Start Cleanup Button
    86→                if emailStore.cleanupStats.hasCleanupOpportunities {
    87→                    Section {
    88→                        NavigationLink {
    89→                            CleanupReviewView()
    90→                        } label: {
    91→                            HStack {
    92→                                Image(systemName: "sparkles")
    93→                                    .foregroundStyle(.blue)
    94→                                Text("Start Guided Cleanup")
    95→                                    .fontWeight(.medium)
    96→                                Spacer()
    97→                                Text("\(emailStore.cleanupStats.totalCleanupCandidates)")
    98→                                    .foregroundStyle(.secondary)
    99→                            }
   100→                        }
   101→                    }
   102→                }
   103→            }
   104→            .navigationTitle("Organize")
   105→            .sheet(item: $selectedFolder) { folder in
   106→                NavigationStack {
   107→                    SmartFolderDetailView(folder: folder)
   108→                        .environmentObject(emailStore)
   109→                }
   110→            }
   111→            .overlay {
   112→                if emailStore.stats.analyzedCount == 0 {
   113→                    ContentUnavailableView(
   114→                        "No Analysis Yet",
   115→                        systemImage: "brain.head.profile",
   116→                        description: Text("Analyze your emails first to see smart folders and cleanup recommendations.")
   117→                    )
   118→                }
   119→            }
   120→        }
   121→    }
   122→}
   123→
   124→// MARK: - Preview
   125→
   126→#Preview {
   127→    SmartFoldersView()
   128→        .environmentObject(EmailStore())
   129→}
   130→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import SwiftUI

// MARK: - Smart Folders View
// Components extracted to: SmartFolderComponents.swift, SmartFolderDetailView.swift

struct SmartFoldersView: View {
    @EnvironmentObject var emailStore: EmailStore
    @State private var selectedFolder: SmartFolder?

    var body: some View {
        NavigationStack {
            List {
                // Cleanup Summary Card
                if emailStore.stats.analyzedCount > 0 {
                    CleanupSummaryCard(stats: emailStore.cleanupStats)
                        .listRowInsets(EdgeInsets())
                        .listRowBackground(Color.clear)
                }

                // Action Required Section
                Section {
                    SmartFolderRow(
                        folder: .requiresAction,
                        count: emailStore.requiresActionEmails.count
                    )
                    .onTapGesture {
                        selectedFolder = .requiresAction
                    }
                } header: {
                    Text("Action Required")
                }

                // Cleanup Section
                Section {
                    SmartFolderRow(
                        folder: .safeToDelete,
                        count: emailStore.safeToDeleteEmails.count
                    )
                    .onTapGesture {
                        selectedFolder = .safeToDelete
                    }

                    SmartFolderRow(
                        folder: .suspicious,
                        count: emailStore.suspiciousEmails.count
                    )
                    .onTapGesture {
                        selectedFolder = .suspicious
                    }

                    SmartFolderRow(
                        folder: .review,
                        count: emailStore.reviewEmails.count
                    )
                    .onTapGesture {
                        selectedFolder = .review
                    }
                } header: {
                    Text("Cleanup Candidates")
                } footer: {
                    Text("AI-analyzed emails ready for cleanup review")
                }

                // Keep Section
                Section {
                    SmartFolderRow(
                        folder: .important,
                        count: emailStore.importantEmails.count
                    )
                    .onTapGesture {
                        selectedFolder = .important
                    }

                    SmartFolderRow(
                        folder: .oldUnread,
                        count: emailStore.oldUnreadEmails.count
                    )
                    .onTapGesture {
                        selectedFolder = .oldUnread
                    }
                } header: {
                    Text("Review")
                }

                // Start Cleanup Button
                if emailStore.cleanupStats.hasCleanupOpportunities {
                    Section {
                        NavigationLink {
                            CleanupReviewView()
                        } label: {
                            HStack {
                                Image(systemName: "sparkles")
                                    .foregroundStyle(.blue)
                                Text("Start Guided Cleanup")
                                    .fontWeight(.medium)
                                Spacer()
                                Text("\(emailStore.cleanupStats.totalCleanupCandidates)")
                                    .foregroundStyle(.secondary)
                            }
                        }
                    }
                }
            }
            .navigationTitle("Organize")
            .sheet(item: $selectedFolder) { folder in
                NavigationStack {
                    SmartFolderDetailView(folder: folder)
                        .environmentObject(emailStore)
                }
            }
            .overlay {
                if emailStore.stats.analyzedCount == 0 {
                    ContentUnavailableView(
                        "No Analysis Yet",
                        systemImage: "brain.head.profile",
                        description: Text("Analyze your emails first to see smart folders and cleanup recommendations.")
                    )
                }
            }
        }
    }
}

// MARK: - Preview

#Preview {
    SmartFoldersView()
        .environmentObject(EmailStore())
}


     1→import SwiftUI
     2→
     3→// MARK: - Cleanup Review View
     4→// Components: CleanupComponents.swift
     5→
     6→struct CleanupReviewView: View {
     7→    @EnvironmentObject var emailStore: EmailStore
     8→    @Environment(\.dismiss) private var dismiss
     9→
    10→    @State private var currentStep: CleanupStep = .safeToDelete
    11→    @State private var selectedEmails: Set<String> = []
    12→    @State private var deletedCount = 0
    13→    @State private var showDeleteConfirmation = false
    14→    @State private var isDeleting = false
    15→    @State private var isComplete = false
    16→
    17→    var emailsForCurrentStep: [Email] {
    18→        switch currentStep {
    19→        case .safeToDelete: return emailStore.safeToDeleteEmails
    20→        case .suspicious: return emailStore.suspiciousEmails
    21→        case .review: return emailStore.reviewEmails
    22→        }
    23→    }
    24→
    25→    var hasNextStep: Bool {
    26→        currentStep.rawValue < CleanupStep.allCases.count - 1
    27→    }
    28→
    29→    var nextStepHasEmails: Bool {
    30→        guard hasNextStep else { return false }
    31→        let nextStep = CleanupStep(rawValue: currentStep.rawValue + 1)!
    32→        switch nextStep {
    33→        case .safeToDelete: return !emailStore.safeToDeleteEmails.isEmpty
    34→        case .suspicious: return !emailStore.suspiciousEmails.isEmpty
    35→        case .review: return !emailStore.reviewEmails.isEmpty
    36→        }
    37→    }
    38→
    39→    var body: some View {
    40→        VStack(spacing: 0) {
    41→            if isComplete {
    42→                completionView
    43→            } else {
    44→                // Progress Indicator
    45→                CleanupProgressIndicator(currentStep: currentStep)
    46→                    .padding()
    47→
    48→                // Step Header
    49→                stepHeader
    50→                    .padding(.horizontal)
    51→
    52→                Divider()
    53→                    .padding(.top)
    54→
    55→                // Email List
    56→                if emailsForCurrentStep.isEmpty {
    57→                    emptyStepView
    58→                } else {
    59→                    emailListView
    60→                }
    61→
    62→                Divider()
    63→
    64→                // Bottom Actions
    65→                bottomActions
    66→                    .padding()
    67→            }
    68→        }
    69→        .navigationTitle("Cleanup Review")
    70→        .navigationBarTitleDisplayMode(.inline)
    71→        .toolbar {
    72→            ToolbarItem(placement: .topBarTrailing) {
    73→                Button("Done") {
    74→                    dismiss()
    75→                }
    76→            }
    77→        }
    78→        .alert("Delete Emails", isPresented: $showDeleteConfirmation) {
    79→            Button("Cancel", role: .cancel) { }
    80→            Button("Delete \(selectedEmails.count)", role: .destructive) {
    81→                deleteSelectedEmails()
    82→            }
    83→        } message: {
    84→            Text("Are you sure you want to delete \(selectedEmails.count) email(s)? This will move them to trash.")
    85→        }
    86→    }
    87→
    88→    // MARK: - Step Header
    89→
    90→    private var stepHeader: some View {
    91→        HStack(spacing: 12) {
    92→            Image(systemName: currentStep.icon)
    93→                .font(.largeTitle)
    94→                .foregroundStyle(currentStep.color)
    95→
    96→            VStack(alignment: .leading, spacing: 4) {
    97→                Text(currentStep.title)
    98→                    .font(.title2.bold())
    99→                Text(currentStep.description)
   100→                    .font(.subheadline)
   101→                    .foregroundStyle(.secondary)
   102→            }
   103→
   104→            Spacer()
   105→
   106→            Text("\(emailsForCurrentStep.count)")
   107→                .font(.title.bold())
   108→                .foregroundStyle(currentStep.color)
   109→        }
   110→    }
   111→
   112→    // MARK: - Email List
   113→
   114→    private var emailListView: some View {
   115→        List {
   116→            // Select All Row
   117→            Button {
   118→                if selectedEmails.count == emailsForCurrentStep.count {
   119→                    selectedEmails.removeAll()
   120→                } else {
   121→                    selectedEmails = Set(emailsForCurrentStep.map { $0.id })
   122→                }
   123→            } label: {
   124→                HStack {
   125→                    Image(systemName: selectedEmails.count == emailsForCurrentStep.count ? "checkmark.circle.fill" : "circle")
   126→                        .foregroundStyle(selectedEmails.count == emailsForCurrentStep.count ? .blue : .secondary)
   127→                    Text("Select All (\(emailsForCurrentStep.count))")
   128→                        .foregroundStyle(.primary)
   129→                    Spacer()
   130→                    if !selectedEmails.isEmpty {
   131→                        Text("\(selectedEmails.count) selected")
   132→                            .font(.caption)
   133→                            .foregroundStyle(.secondary)
   134→                    }
   135→                }
   136→            }
   137→            .buttonStyle(.plain)
   138→
   139→            // Email Rows
   140→            ForEach(emailsForCurrentStep) { email in
   141→                CleanupEmailRow(
   142→                    email: email,
   143→                    isSelected: selectedEmails.contains(email.id),
   144→                    onToggle: {
   145→                        if selectedEmails.contains(email.id) {
   146→                            selectedEmails.remove(email.id)
   147→                        } else {
   148→                            selectedEmails.insert(email.id)
   149→                        }
   150→                    }
   151→                )
   152→            }
   153→        }
   154→        .listStyle(.plain)
   155→    }
   156→
   157→    // MARK: - Empty Step View
   158→
   159→    private var emptyStepView: some View {
   160→        VStack(spacing: 16) {
   161→            Spacer()
   162→
   163→            Image(systemName: "checkmark.circle.fill")
   164→                .font(.system(size: 60, weight: .medium, design: .rounded))
   165→                .foregroundStyle(.green)
   166→                .accessibilityHidden(true)
   167→
   168→            Text("All Clear!")
   169→                .font(.title2.bold())
   170→
   171→            Text("No emails in this category")
   172→                .font(.subheadline)
   173→                .foregroundStyle(.secondary)
   174→
   175→            Spacer()
   176→        }
   177→        .frame(maxWidth: .infinity)
   178→    }
   179→
   180→    // MARK: - Bottom Actions
   181→
   182→    private var bottomActions: some View {
   183→        HStack(spacing: 16) {
   184→            // Delete Button
   185→            Button {
   186→                showDeleteConfirmation = true
   187→            } label: {
   188→                HStack {
   189→                    if isDeleting {
   190→                        ProgressView()
   191→                            .scaleEffect(0.8)
   192→                    } else {
   193→                        Image(systemName: "trash")
   194→                    }
   195→                    Text("Delete Selected")
   196→                }
   197→                .frame(maxWidth: .infinity)
   198→            }
   199→            .buttonStyle(.borderedProminent)
   200→            .tint(.red)
   201→            .disabled(selectedEmails.isEmpty || isDeleting)
   202→
   203→            // Skip/Next Button
   204→            if hasNextStep || !isComplete {
   205→                Button {
   206→                    goToNextStep()
   207→                } label: {
   208→                    HStack {
   209→                        Text(hasNextStep ? "Skip" : "Finish")
   210→                        Image(systemName: hasNextStep ? "arrow.right" : "checkmark")
   211→                    }
   212→                    .frame(maxWidth: .infinity)
   213→                }
   214→                .buttonStyle(.bordered)
   215→            }
   216→        }
   217→    }
   218→
   219→    // MARK: - Completion View
   220→
   221→    private var completionView: some View {
   222→        VStack(spacing: 24) {
   223→            Spacer()
   224→
   225→            Image(systemName: "checkmark.seal.fill")
   226→                .font(.system(size: 80, weight: .medium, design: .rounded))
   227→                .foregroundStyle(.green)
   228→                .accessibilityHidden(true)
   229→
   230→            Text("Cleanup Complete!")
   231→                .font(.largeTitle.bold())
   232→
   233→            if deletedCount > 0 {
   234→                Text("You deleted \(deletedCount) email\(deletedCount == 1 ? "" : "s")")
   235→                    .font(.title3)
   236→                    .foregroundStyle(.secondary)
   237→            } else {
   238→                Text("Your inbox is organized")
   239→                    .font(.title3)
   240→                    .foregroundStyle(.secondary)
   241→            }
   242→
   243→            // Summary Stats
   244→            VStack(spacing: 12) {
   245→                CleanupStatRow(label: "Safe to Delete", count: emailStore.safeToDeleteEmails.count, color: .green)
   246→                CleanupStatRow(label: "Suspicious", count: emailStore.suspiciousEmails.count, color: .red)
   247→                CleanupStatRow(label: "Review", count: emailStore.reviewEmails.count, color: .yellow)
   248→            }
   249→            .padding()
   250→            .background(Color(.secondarySystemBackground), in: RoundedRectangle(cornerRadius: 12))
   251→            .padding(.horizontal)
   252→
   253→            Spacer()
   254→
   255→            Button {
   256→                dismiss()
   257→            } label: {
   258→                Text("Done")
   259→                    .frame(maxWidth: .infinity)
   260→            }
   261→            .buttonStyle(.borderedProminent)
   262→            .padding(.horizontal)
   263→        }
   264→        .padding()
   265→    }
   266→
   267→    // MARK: - Actions
   268→
   269→    private func deleteSelectedEmails() {
   270→        let idsToDelete = selectedEmails
   271→        Task {
   272→            isDeleting = true
   273→            let emailsToDelete = emailStore.emails.filter { idsToDelete.contains($0.id) }
   274→            let count = await emailStore.deleteEmailsBatch(emailsToDelete)
   275→
   276→            await MainActor.run {
   277→                deletedCount += count
   278→                selectedEmails.removeAll()
   279→                isDeleting = false
   280→
   281→                // Auto-advance if step is now empty
   282→                if emailsForCurrentStep.isEmpty && hasNextStep {
   283→                    goToNextStep()
   284→                }
   285→            }
   286→        }
   287→    }
   288→
   289→    private func goToNextStep() {
   290→        selectedEmails.removeAll()
   291→
   292→        if hasNextStep {
   293→            withAnimation {
   294→                currentStep = CleanupStep(rawValue: currentStep.rawValue + 1)!
   295→            }
   296→        } else {
   297→            withAnimation {
   298→                isComplete = true
   299→            }
   300→        }
   301→    }
   302→}
   303→
   304→// MARK: - Preview
   305→
   306→#Preview {
   307→    NavigationStack {
   308→        CleanupReviewView()
   309→            .environmentObject(EmailStore())
   310→    }
   311→}
   312→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import SwiftUI

// MARK: - Cleanup Review View
// Components: CleanupComponents.swift

struct CleanupReviewView: View {
    @EnvironmentObject var emailStore: EmailStore
    @Environment(\.dismiss) private var dismiss

    @State private var currentStep: CleanupStep = .safeToDelete
    @State private var selectedEmails: Set<String> = []
    @State private var deletedCount = 0
    @State private var showDeleteConfirmation = false
    @State private var isDeleting = false
    @State private var isComplete = false

    var emailsForCurrentStep: [Email] {
        switch currentStep {
        case .safeToDelete: return emailStore.safeToDeleteEmails
        case .suspicious: return emailStore.suspiciousEmails
        case .review: return emailStore.reviewEmails
        }
    }

    var hasNextStep: Bool {
        currentStep.rawValue < CleanupStep.allCases.count - 1
    }

    var nextStepHasEmails: Bool {
        guard hasNextStep else { return false }
        let nextStep = CleanupStep(rawValue: currentStep.rawValue + 1)!
        switch nextStep {
        case .safeToDelete: return !emailStore.safeToDeleteEmails.isEmpty
        case .suspicious: return !emailStore.suspiciousEmails.isEmpty
        case .review: return !emailStore.reviewEmails.isEmpty
        }
    }

    var body: some View {
        VStack(spacing: 0) {
            if isComplete {
                completionView
            } else {
                // Progress Indicator
                CleanupProgressIndicator(currentStep: currentStep)
                    .padding()

                // Step Header
                stepHeader
                    .padding(.horizontal)

                Divider()
                    .padding(.top)

                // Email List
                if emailsForCurrentStep.isEmpty {
                    emptyStepView
                } else {
                    emailListView
                }

                Divider()

                // Bottom Actions
                bottomActions
                    .padding()
            }
        }
        .navigationTitle("Cleanup Review")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                Button("Done") {
                    dismiss()
                }
            }
        }
        .alert("Delete Emails", isPresented: $showDeleteConfirmation) {
            Button("Cancel", role: .cancel) { }
            Button("Delete \(selectedEmails.count)", role: .destructive) {
                deleteSelectedEmails()
            }
        } message: {
            Text("Are you sure you want to delete \(selectedEmails.count) email(s)? This will move them to trash.")
        }
    }

    // MARK: - Step Header

    private var stepHeader: some View {
        HStack(spacing: 12) {
            Image(systemName: currentStep.icon)
                .font(.largeTitle)
                .foregroundStyle(currentStep.color)

            VStack(alignment: .leading, spacing: 4) {
                Text(currentStep.title)
                    .font(.title2.bold())
                Text(currentStep.description)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }

            Spacer()

            Text("\(emailsForCurrentStep.count)")
                .font(.title.bold())
                .foregroundStyle(currentStep.color)
        }
    }

    // MARK: - Email List

    private var emailListView: some View {
        List {
            // Select All Row
            Button {
                if selectedEmails.count == emailsForCurrentStep.count {
                    selectedEmails.removeAll()
                } else {
                    selectedEmails = Set(emailsForCurrentStep.map { $0.id })
                }
            } label: {
                HStack {
                    Image(systemName: selectedEmails.count == emailsForCurrentStep.count ? "checkmark.circle.fill" : "circle")
                        .foregroundStyle(selectedEmails.count == emailsForCurrentStep.count ? .blue : .secondary)
                    Text("Select All (\(emailsForCurrentStep.count))")
                        .foregroundStyle(.primary)
                    Spacer()
                    if !selectedEmails.isEmpty {
                        Text("\(selectedEmails.count) selected")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                    }
                }
            }
            .buttonStyle(.plain)

            // Email Rows
            ForEach(emailsForCurrentStep) { email in
                CleanupEmailRow(
                    email: email,
                    isSelected: selectedEmails.contains(email.id),
                    onToggle: {
                        if selectedEmails.contains(email.id) {
                            selectedEmails.remove(email.id)
                        } else {
                            selectedEmails.insert(email.id)
                        }
                    }
                )
            }
        }
        .listStyle(.plain)
    }

    // MARK: - Empty Step View

    private var emptyStepView: some View {
        VStack(spacing: 16) {
            Spacer()

            Image(systemName: "checkmark.circle.fill")
                .font(.system(size: 60, weight: .medium, design: .rounded))
                .foregroundStyle(.green)
                .accessibilityHidden(true)

            Text("All Clear!")
                .font(.title2.bold())

            Text("No emails in this category")
                .font(.subheadline)
                .foregroundStyle(.secondary)

            Spacer()
        }
        .frame(maxWidth: .infinity)
    }

    // MARK: - Bottom Actions

    private var bottomActions: some View {
        HStack(spacing: 16) {
            // Delete Button
            Button {
                showDeleteConfirmation = true
            } label: {
                HStack {
                    if isDeleting {
                        ProgressView()
                            .scaleEffect(0.8)
                    } else {
                        Image(systemName: "trash")
                    }
                    Text("Delete Selected")
                }
                .frame(maxWidth: .infinity)
            }
            .buttonStyle(.borderedProminent)
            .tint(.red)
            .disabled(selectedEmails.isEmpty || isDeleting)

            // Skip/Next Button
            if hasNextStep || !isComplete {
                Button {
                    goToNextStep()
                } label: {
                    HStack {
                        Text(hasNextStep ? "Skip" : "Finish")
                        Image(systemName: hasNextStep ? "arrow.right" : "checkmark")
                    }
                    .frame(maxWidth: .infinity)
                }
                .buttonStyle(.bordered)
            }
        }
    }

    // MARK: - Completion View

    private var completionView: some View {
        VStack(spacing: 24) {
            Spacer()

            Image(systemName: "checkmark.seal.fill")
                .font(.system(size: 80, weight: .medium, design: .rounded))
                .foregroundStyle(.green)
                .accessibilityHidden(true)

            Text("Cleanup Complete!")
                .font(.largeTitle.bold())

            if deletedCount > 0 {
                Text("You deleted \(deletedCount) email\(deletedCount == 1 ? "" : "s")")
                    .font(.title3)
                    .foregroundStyle(.secondary)
            } else {
                Text("Your inbox is organized")
                    .font(.title3)
                    .foregroundStyle(.secondary)
            }

            // Summary Stats
            VStack(spacing: 12) {
                CleanupStatRow(label: "Safe to Delete", count: emailStore.safeToDeleteEmails.count, color: .green)
                CleanupStatRow(label: "Suspicious", count: emailStore.suspiciousEmails.count, color: .red)
                CleanupStatRow(label: "Review", count: emailStore.reviewEmails.count, color: .yellow)
            }
            .padding()
            .background(Color(.secondarySystemBackground), in: RoundedRectangle(cornerRadius: 12))
            .padding(.horizontal)

            Spacer()

            Button {
                dismiss()
            } label: {
                Text("Done")
                    .frame(maxWidth: .infinity)
            }
            .buttonStyle(.borderedProminent)
            .padding(.horizontal)
        }
        .padding()
    }

    // MARK: - Actions

    private func deleteSelectedEmails() {
        let idsToDelete = selectedEmails
        Task {
            isDeleting = true
            let emailsToDelete = emailStore.emails.filter { idsToDelete.contains($0.id) }
            let count = await emailStore.deleteEmailsBatch(emailsToDelete)

            await MainActor.run {
                deletedCount += count
                selectedEmails.removeAll()
                isDeleting = false

                // Auto-advance if step is now empty
                if emailsForCurrentStep.isEmpty && hasNextStep {
                    goToNextStep()
                }
            }
        }
    }

    private func goToNextStep() {
        selectedEmails.removeAll()

        if hasNextStep {
            withAnimation {
                currentStep = CleanupStep(rawValue: currentStep.rawValue + 1)!
            }
        } else {
            withAnimation {
                isComplete = true
            }
        }
    }
}

// MARK: - Preview

#Preview {
    NavigationStack {
        CleanupReviewView()
            .environmentObject(EmailStore())
    }
}


Let me check a few more key files to complete the understanding:


     1→import Foundation
     2→
     3→// MARK: - EmailStore Analysis Extension
     4→
     5→extension EmailStore {
     6→
     7→    // MARK: - Single Email Analysis
     8→
     9→    func analyzeEmail(_ email: Email) async {
    10→        guard let index = emails.firstIndex(where: { $0.id == email.id }) else { return }
    11→
    12→        do {
    13→            let analysis = try await aiService.analyzeEmail(email)
    14→            emails[index].analysis = analysis
    15→
    16→            // Save analysis to cache
    17→            cacheService.updateAnalysis(for: email.id, analysis: analysis)
    18→
    19→            updateStats()
    20→        } catch {
    21→            self.error = "Analysis failed: \(error.localizedDescription)"
    22→        }
    23→    }
    24→
    25→    // MARK: - Batch Analysis
    26→
    27→    /// Analyze all emails sequentially (legacy, slower)
    28→    func analyzeAllEmails() async {
    29→        await analyzeAllEmailsBatch()
    30→    }
    31→
    32→    /// Analyze all unanalyzed emails in parallel (5-6x faster)
    33→    /// - Parameter onProgress: Progress callback (0.0 to 1.0)
    34→    func analyzeAllEmailsBatch(onProgress: ((Double) -> Void)? = nil) async {
    35→        let pendingEmails = emails.filter { $0.analysis == nil }
    36→        guard !pendingEmails.isEmpty else {
    37→            onProgress?(1.0)
    38→            return
    39→        }
    40→
    41→        AppLogger.log("Starting batch analysis of \(pendingEmails.count) emails...", category: .analysis)
    42→        let startTime = Date()
    43→
    44→        // Process all pending emails in parallel with progress tracking
    45→        let results = await aiService.analyzeEmailsBatch(pendingEmails) { progress in
    46→            Task { @MainActor in
    47→                onProgress?(progress)
    48→            }
    49→        }
    50→
    51→        // Update emails in memory
    52→        var updatedCount = 0
    53→        for (emailId, analysis) in results {
    54→            if let index = emails.firstIndex(where: { $0.id == emailId }) {
    55→                emails[index].analysis = analysis
    56→                updatedCount += 1
    57→            }
    58→        }
    59→
    60→        // Batch save to cache (single disk write)
    61→        cacheService.updateAnalysesBatch(results)
    62→
    63→        // Update stats
    64→        updateStats()
    65→
    66→        let elapsed = Date().timeIntervalSince(startTime)
    67→        AppLogger.log("Batch analysis complete: \(updatedCount) emails in \(String(format: "%.1f", elapsed))s", category: .analysis)
    68→
    69→        // Final progress update
    70→        onProgress?(1.0)
    71→    }
    72→
    73→    /// Analyze a batch of specific emails (for partial analysis)
    74→    func analyzeEmailsBatch(_ emailsToAnalyze: [Email], onProgress: ((Double) -> Void)? = nil) async {
    75→        guard !emailsToAnalyze.isEmpty else { return }
    76→
    77→        let results = await aiService.analyzeEmailsBatch(emailsToAnalyze) { progress in
    78→            Task { @MainActor in
    79→                onProgress?(progress)
    80→            }
    81→        }
    82→
    83→        // Update emails in memory
    84→        for (emailId, analysis) in results {
    85→            if let index = emails.firstIndex(where: { $0.id == emailId }) {
    86→                emails[index].analysis = analysis
    87→            }
    88→        }
    89→
    90→        // Batch save to cache
    91→        cacheService.updateAnalysesBatch(results)
    92→
    93→        updateStats()
    94→    }
    95→
    96→    // MARK: - Live Analysis with Real-Time Updates
    97→
    98→    /// Analyze all unanalyzed emails with live updates, pause/resume support
    99→    func analyzeAllEmailsWithLiveUpdates() async {
   100→        // Check if resuming from pause
   101→        var pendingEmails: [Email]
   102→        if analysisState.state == .paused {
   103→            let resumeIds = analysisState.resume()
   104→            pendingEmails = emails.filter { resumeIds.contains($0.id) }
   105→            AppLogger.log("Resuming analysis with \(pendingEmails.count) emails", category: .analysis)
   106→        } else {
   107→            pendingEmails = emails.filter { $0.analysis == nil }
   108→            guard !pendingEmails.isEmpty else {
   109→                AppLogger.log("All emails already analyzed", category: .analysis)
   110→                return
   111→            }
   112→            analysisState.startAnalysis(pendingCount: pendingEmails.count)
   113→        }
   114→
   115→        // Create and store the task for cancellation
   116→        let task = Task { [weak self] in
   117→            guard let self = self else { return }
   118→
   119→            let (results, remainingIds) = await self.aiService.analyzeEmailsBatchWithEvents(
   120→                pendingEmails,
   121→                maxConcurrent: 5
   122→            ) { [weak self] event in
   123→                guard let self = self else { return }
   124→
   125→                Task { @MainActor in
   126→                    self.handleAnalysisEvent(event)
   127→                }
   128→            }
   129→
   130→            // Handle completion
   131→            await MainActor.run {
   132→                if remainingIds.isEmpty {
   133→                    // All done
   134→                    self.analysisState.complete()
   135→
   136→                    // Final cache save
   137→                    self.cacheService.updateAnalysesBatch(results)
   138→                    self.updateStats()
   139→                } else {
   140→                    // Was paused - remaining emails stored in analysisState
   141→                    self.analysisState.pause(remainingEmailIds: remainingIds)
   142→                }
   143→            }
   144→        }
   145→
   146→        analysisState.setCurrentTask(task)
   147→        await task.value
   148→    }
   149→
   150→    /// Handle analysis events for live updates
   151→    func handleAnalysisEvent(_ event: AnalysisEvent) {
   152→        switch event {
   153→        case .started(let email):
   154→            // Add "analyzing" log entry
   155→            let logEntry = AnalysisLogEntry.analyzing(email: email)
   156→            analysisState.addLog(logEntry)
   157→
   158→        case .completed(let email, let analysis, let duration):
   159→            // Update email in memory (UI updates immediately)
   160→            if let index = emails.firstIndex(where: { $0.id == email.id }) {
   161→                emails[index].analysis = analysis
   162→                // Cache is saved in batch at end (see line ~137) to avoid N+1 I/O operations
   163→            }
   164→
   165→            // Update log entry
   166→            let logEntry = AnalysisLogEntry.completed(email: email, analysis: analysis, duration: duration)
   167→            analysisState.updateLog(emailId: email.id, with: logEntry)
   168→
   169→            // Increment counters
   170→            analysisState.incrementProcessed(success: true)
   171→
   172→            // Throttled stats update
   173→            updateStatsThrottled()
   174→
   175→        case .failed(let email, let errorMsg, let duration):
   176→            // Update log entry
   177→            let logEntry = AnalysisLogEntry.failed(email: email, error: errorMsg, duration: duration)
   178→            analysisState.updateLog(emailId: email.id, with: logEntry)
   179→
   180→            // Increment counters
   181→            analysisState.incrementProcessed(success: false)
   182→
   183→            // Throttled stats update
   184→            updateStatsThrottled()
   185→
   186→        case .progress(let completed, let total):
   187→            analysisState.progress = total > 0 ? Double(completed) / Double(total) : 0
   188→        }
   189→    }
   190→
   191→    /// Update stats with throttling (max every 100ms)
   192→    func updateStatsThrottled() {
   193→        let now = Date()
   194→        if now.timeIntervalSince(lastStatsUpdate) >= statsUpdateInterval {
   195→            lastStatsUpdate = now
   196→            updateStats()
   197→        }
   198→    }
   199→
   200→    // MARK: - Analysis Control
   201→
   202→    /// Pause the current analysis
   203→    func pauseAnalysis() {
   204→        analysisState.currentTask?.cancel()
   205→        // The task will detect cancellation and call pause() with remaining IDs
   206→    }
   207→
   208→    /// Resume paused analysis
   209→    func resumeAnalysis() async {
   210→        guard analysisState.state == .paused else { return }
   211→        await analyzeAllEmailsWithLiveUpdates()
   212→    }
   213→
   214→    /// Cancel and reset analysis
   215→    func cancelAnalysis() {
   216→        analysisState.cancel()
   217→    }
   218→}
   219→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import Foundation

// MARK: - EmailStore Analysis Extension

extension EmailStore {

    // MARK: - Single Email Analysis

    func analyzeEmail(_ email: Email) async {
        guard let index = emails.firstIndex(where: { $0.id == email.id }) else { return }

        do {
            let analysis = try await aiService.analyzeEmail(email)
            emails[index].analysis = analysis

            // Save analysis to cache
            cacheService.updateAnalysis(for: email.id, analysis: analysis)

            updateStats()
        } catch {
            self.error = "Analysis failed: \(error.localizedDescription)"
        }
    }

    // MARK: - Batch Analysis

    /// Analyze all emails sequentially (legacy, slower)
    func analyzeAllEmails() async {
        await analyzeAllEmailsBatch()
    }

    /// Analyze all unanalyzed emails in parallel (5-6x faster)
    /// - Parameter onProgress: Progress callback (0.0 to 1.0)
    func analyzeAllEmailsBatch(onProgress: ((Double) -> Void)? = nil) async {
        let pendingEmails = emails.filter { $0.analysis == nil }
        guard !pendingEmails.isEmpty else {
            onProgress?(1.0)
            return
        }

        AppLogger.log("Starting batch analysis of \(pendingEmails.count) emails...", category: .analysis)
        let startTime = Date()

        // Process all pending emails in parallel with progress tracking
        let results = await aiService.analyzeEmailsBatch(pendingEmails) { progress in
            Task { @MainActor in
                onProgress?(progress)
            }
        }

        // Update emails in memory
        var updatedCount = 0
        for (emailId, analysis) in results {
            if let index = emails.firstIndex(where: { $0.id == emailId }) {
                emails[index].analysis = analysis
                updatedCount += 1
            }
        }

        // Batch save to cache (single disk write)
        cacheService.updateAnalysesBatch(results)

        // Update stats
        updateStats()

        let elapsed = Date().timeIntervalSince(startTime)
        AppLogger.log("Batch analysis complete: \(updatedCount) emails in \(String(format: "%.1f", elapsed))s", category: .analysis)

        // Final progress update
        onProgress?(1.0)
    }

    /// Analyze a batch of specific emails (for partial analysis)
    func analyzeEmailsBatch(_ emailsToAnalyze: [Email], onProgress: ((Double) -> Void)? = nil) async {
        guard !emailsToAnalyze.isEmpty else { return }

        let results = await aiService.analyzeEmailsBatch(emailsToAnalyze) { progress in
            Task { @MainActor in
                onProgress?(progress)
            }
        }

        // Update emails in memory
        for (emailId, analysis) in results {
            if let index = emails.firstIndex(where: { $0.id == emailId }) {
                emails[index].analysis = analysis
            }
        }

        // Batch save to cache
        cacheService.updateAnalysesBatch(results)

        updateStats()
    }

    // MARK: - Live Analysis with Real-Time Updates

    /// Analyze all unanalyzed emails with live updates, pause/resume support
    func analyzeAllEmailsWithLiveUpdates() async {
        // Check if resuming from pause
        var pendingEmails: [Email]
        if analysisState.state == .paused {
            let resumeIds = analysisState.resume()
            pendingEmails = emails.filter { resumeIds.contains($0.id) }
            AppLogger.log("Resuming analysis with \(pendingEmails.count) emails", category: .analysis)
        } else {
            pendingEmails = emails.filter { $0.analysis == nil }
            guard !pendingEmails.isEmpty else {
                AppLogger.log("All emails already analyzed", category: .analysis)
                return
            }
            analysisState.startAnalysis(pendingCount: pendingEmails.count)
        }

        // Create and store the task for cancellation
        let task = Task { [weak self] in
            guard let self = self else { return }

            let (results, remainingIds) = await self.aiService.analyzeEmailsBatchWithEvents(
                pendingEmails,
                maxConcurrent: 5
            ) { [weak self] event in
                guard let self = self else { return }

                Task { @MainActor in
                    self.handleAnalysisEvent(event)
                }
            }

            // Handle completion
            await MainActor.run {
                if remainingIds.isEmpty {
                    // All done
                    self.analysisState.complete()

                    // Final cache save
                    self.cacheService.updateAnalysesBatch(results)
                    self.updateStats()
                } else {
                    // Was paused - remaining emails stored in analysisState
                    self.analysisState.pause(remainingEmailIds: remainingIds)
                }
            }
        }

        analysisState.setCurrentTask(task)
        await task.value
    }

    /// Handle analysis events for live updates
    func handleAnalysisEvent(_ event: AnalysisEvent) {
        switch event {
        case .started(let email):
            // Add "analyzing" log entry
            let logEntry = AnalysisLogEntry.analyzing(email: email)
            analysisState.addLog(logEntry)

        case .completed(let email, let analysis, let duration):
            // Update email in memory (UI updates immediately)
            if let index = emails.firstIndex(where: { $0.id == email.id }) {
                emails[index].analysis = analysis
                // Cache is saved in batch at end (see line ~137) to avoid N+1 I/O operations
            }

            // Update log entry
            let logEntry = AnalysisLogEntry.completed(email: email, analysis: analysis, duration: duration)
            analysisState.updateLog(emailId: email.id, with: logEntry)

            // Increment counters
            analysisState.incrementProcessed(success: true)

            // Throttled stats update
            updateStatsThrottled()

        case .failed(let email, let errorMsg, let duration):
            // Update log entry
            let logEntry = AnalysisLogEntry.failed(email: email, error: errorMsg, duration: duration)
            analysisState.updateLog(emailId: email.id, with: logEntry)

            // Increment counters
            analysisState.incrementProcessed(success: false)

            // Throttled stats update
            updateStatsThrottled()

        case .progress(let completed, let total):
            analysisState.progress = total > 0 ? Double(completed) / Double(total) : 0
        }
    }

    /// Update stats with throttling (max every 100ms)
    func updateStatsThrottled() {
        let now = Date()
        if now.timeIntervalSince(lastStatsUpdate) >= statsUpdateInterval {
            lastStatsUpdate = now
            updateStats()
        }
    }

    // MARK: - Analysis Control

    /// Pause the current analysis
    func pauseAnalysis() {
        analysisState.currentTask?.cancel()
        // The task will detect cancellation and call pause() with remaining IDs
    }

    /// Resume paused analysis
    func resumeAnalysis() async {
        guard analysisState.state == .paused else { return }
        await analyzeAllEmailsWithLiveUpdates()
    }

    /// Cancel and reset analysis
    func cancelAnalysis() {
        analysisState.cancel()
    }
}