     1→import SwiftUI
     2→
     3→struct ValidationProgressView: View {
     4→    let progress: ValidationProgress
     5→
     6→    var body: some View {
     7→        VStack(spacing: 20) {
     8→            // Progress Ring
     9→            ZStack {
    10→                // Background ring
    11→                Circle()
    12→                    .stroke(Color.gray.opacity(0.2), lineWidth: 16)
    13→
    14→                // Progress ring
    15→                Circle()
    16→                    .trim(from: 0, to: progress.percentComplete)
    17→                    .stroke(
    18→                        AngularGradient(
    19→                            colors: [.green, .blue, .green],
    20→                            center: .center
    21→                        ),
    22→                        style: StrokeStyle(lineWidth: 16, lineCap: .round)
    23→                    )
    24→                    .rotationEffect(.degrees(-90))
    25→                    .animation(.spring(duration: 0.3), value: progress.percentComplete)
    26→
    27→                // Center content
    28→                VStack(spacing: 4) {
    29→                    Text("\(Int(progress.percentComplete * 100))%")
    30→                        .font(.system(size: 36, weight: .bold, design: .rounded))
    31→                        .contentTransition(.numericText())
    32→
    33→                    Text("\(progress.processed.formatted()) / \(progress.total.formatted())")
    34→                        .font(.caption)
    35→                        .foregroundStyle(.secondary)
    36→                }
    37→            }
    38→            .frame(width: 150, height: 150)
    39→
    40→            // Status Distribution Bar
    41→            GeometryReader { geometry in
    42→                HStack(spacing: 2) {
    43→                    let total = max(1, progress.processed)
    44→                    let width = geometry.size.width
    45→
    46→                    Rectangle()
    47→                        .fill(Color.green)
    48→                        .frame(width: width * CGFloat(progress.onlineCount) / CGFloat(total))
    49→
    50→                    Rectangle()
    51→                        .fill(Color.red)
    52→                        .frame(width: width * CGFloat(progress.offlineCount) / CGFloat(total))
    53→
    54→                    Rectangle()
    55→                        .fill(Color.purple)
    56→                        .frame(width: width * CGFloat(progress.errorCount) / CGFloat(total))
    57→
    58→                    // Remaining (pending in current batch)
    59→                    Rectangle()
    60→                        .fill(Color.gray.opacity(0.3))
    61→                }
    62→                .clipShape(Capsule())
    63→            }
    64→            .frame(height: 8)
    65→
    66→            // Metrics Row
    67→            HStack(spacing: 32) {
    68→                MetricCard(
    69→                    label: "Speed",
    70→                    value: String(format: "%.1f/sec", progress.domainsPerSecond),
    71→                    icon: "speedometer"
    72→                )
    73→
    74→                MetricCard(
    75→                    label: "ETA",
    76→                    value: progress.formattedETA,
    77→                    icon: "clock"
    78→                )
    79→
    80→                MetricCard(
    81→                    label: "Online",
    82→                    value: progress.onlineCount.formatted(),
    83→                    color: .green
    84→                )
    85→
    86→                MetricCard(
    87→                    label: "Offline",
    88→                    value: progress.offlineCount.formatted(),
    89→                    color: .red
    90→                )
    91→            }
    92→        }
    93→    }
    94→}
    95→
    96→struct ProgressRing: View {
    97→    let progress: Double
    98→    let lineWidth: CGFloat
    99→    var gradientColors: [Color] = [.green, .blue, .green]
   100→
   101→    var body: some View {
   102→        ZStack {
   103→            Circle()
   104→                .stroke(Color.gray.opacity(0.2), lineWidth: lineWidth)
   105→
   106→            Circle()
   107→                .trim(from: 0, to: progress)
   108→                .stroke(
   109→                    AngularGradient(colors: gradientColors, center: .center),
   110→                    style: StrokeStyle(lineWidth: lineWidth, lineCap: .round)
   111→                )
   112→                .rotationEffect(.degrees(-90))
   113→                .animation(.spring(duration: 0.3), value: progress)
   114→        }
   115→    }
   116→}
   117→
   118→struct LiveCountBadge: View {
   119→    let count: Int
   120→    let label: String
   121→    let color: Color
   122→
   123→    var body: some View {
   124→        VStack(spacing: 2) {
   125→            Text(count.formatted())
   126→                .font(.title2.bold().monospacedDigit())
   127→                .foregroundStyle(color)
   128→                .contentTransition(.numericText())
   129→
   130→            Text(label)
   131→                .font(.caption2)
   132→                .foregroundStyle(.secondary)
   133→        }
   134→        .padding(.horizontal, 12)
   135→        .padding(.vertical, 8)
   136→        .background(color.opacity(0.1))
   137→        .clipShape(RoundedRectangle(cornerRadius: 8))
   138→    }
   139→}
   140→
   141→#Preview {
   142→    ValidationProgressView(
   143→        progress: ValidationProgress(
   144→            processed: 68234,
   145→            total: 300000,
   146→            onlineCount: 45230,
   147→            offlineCount: 20004,
   148→            errorCount: 3000,
   149→            domainsPerSecond: 112.5,
   150→            estimatedSecondsRemaining: 2064
   151→        )
   152→    )
   153→    .padding()
   154→    .frame(width: 500)
   155→}
   156→

<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

struct ValidationProgressView: View {
    let progress: ValidationProgress

    var body: some View {
        VStack(spacing: 20) {
            // Progress Ring
            ZStack {
                // Background ring
                Circle()
                    .stroke(Color.gray.opacity(0.2), lineWidth: 16)

                // Progress ring
                Circle()
                    .trim(from: 0, to: progress.percentComplete)
                    .stroke(
                        AngularGradient(
                            colors: [.green, .blue, .green],
                            center: .center
                        ),
                        style: StrokeStyle(lineWidth: 16, lineCap: .round)
                    )
                    .rotationEffect(.degrees(-90))
                    .animation(.spring(duration: 0.3), value: progress.percentComplete)

                // Center content
                VStack(spacing: 4) {
                    Text("\(Int(progress.percentComplete * 100))%")
                        .font(.system(size: 36, weight: .bold, design: .rounded))
                        .contentTransition(.numericText())

                    Text("\(progress.processed.formatted()) / \(progress.total.formatted())")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }
            .frame(width: 150, height: 150)

            // Status Distribution Bar
            GeometryReader { geometry in
                HStack(spacing: 2) {
                    let total = max(1, progress.processed)
                    let width = geometry.size.width

                    Rectangle()
                        .fill(Color.green)
                        .frame(width: width * CGFloat(progress.onlineCount) / CGFloat(total))

                    Rectangle()
                        .fill(Color.red)
                        .frame(width: width * CGFloat(progress.offlineCount) / CGFloat(total))

                    Rectangle()
                        .fill(Color.purple)
                        .frame(width: width * CGFloat(progress.errorCount) / CGFloat(total))

                    // Remaining (pending in current batch)
                    Rectangle()
                        .fill(Color.gray.opacity(0.3))
                }
                .clipShape(Capsule())
            }
            .frame(height: 8)

            // Metrics Row
            HStack(spacing: 32) {
                MetricCard(
                    label: "Speed",
                    value: String(format: "%.1f/sec", progress.domainsPerSecond),
                    icon: "speedometer"
                )

                MetricCard(
                    label: "ETA",
                    value: progress.formattedETA,
                    icon: "clock"
                )

                MetricCard(
                    label: "Online",
                    value: progress.onlineCount.formatted(),
                    color: .green
                )

                MetricCard(
                    label: "Offline",
                    value: progress.offlineCount.formatted(),
                    color: .red
                )
            }
        }
    }
}

struct ProgressRing: View {
    let progress: Double
    let lineWidth: CGFloat
    var gradientColors: [Color] = [.green, .blue, .green]

    var body: some View {
        ZStack {
            Circle()
                .stroke(Color.gray.opacity(0.2), lineWidth: lineWidth)

            Circle()
                .trim(from: 0, to: progress)
                .stroke(
                    AngularGradient(colors: gradientColors, center: .center),
                    style: StrokeStyle(lineWidth: lineWidth, lineCap: .round)
                )
                .rotationEffect(.degrees(-90))
                .animation(.spring(duration: 0.3), value: progress)
        }
    }
}

struct LiveCountBadge: View {
    let count: Int
    let label: String
    let color: Color

    var body: some View {
        VStack(spacing: 2) {
            Text(count.formatted())
                .font(.title2.bold().monospacedDigit())
                .foregroundStyle(color)
                .contentTransition(.numericText())

            Text(label)
                .font(.caption2)
                .foregroundStyle(.secondary)
        }
        .padding(.horizontal, 12)
        .padding(.vertical, 8)
        .background(color.opacity(0.1))
        .clipShape(RoundedRectangle(cornerRadius: 8))
    }
}

#Preview {
    ValidationProgressView(
        progress: ValidationProgress(
            processed: 68234,
            total: 300000,
            onlineCount: 45230,
            offlineCount: 20004,
            errorCount: 3000,
            domainsPerSecond: 112.5,
            estimatedSecondsRemaining: 2064
        )
    )
    .padding()
    .frame(width: 500)
}


     1→import SwiftUI
     2→
     3→struct ContentView: View {
     4→    @EnvironmentObject var dataManager: DataManager
     5→
     6→    @State private var selectedSidebarItem: SidebarItem = .overview
     7→    @State private var searchText = ""
     8→    @State private var isImporting = false
     9→    @State private var isExporting = false
    10→    @State private var isValidating = false
    11→    @State private var isPaused = false
    12→    @State private var showingImportSheet = false
    13→    @State private var showingExportSheet = false
    14→
    15→    var body: some View {
    16→        NavigationSplitView {
    17→            SidebarView(selection: $selectedSidebarItem)
    18→        } detail: {
    19→            detailView
    20→                .searchable(text: $searchText, prompt: "Search domains...")
    21→        }
    22→        .toolbar {
    23→            toolbarContent
    24→        }
    25→        .sheet(isPresented: $showingImportSheet) {
    26→            ImportView()
    27→        }
    28→        .sheet(isPresented: $showingExportSheet) {
    29→            ExportOptionsView()
    30→        }
    31→        .onReceive(NotificationCenter.default.publisher(for: .importDomains)) { _ in
    32→            showingImportSheet = true
    33→        }
    34→        .onReceive(NotificationCenter.default.publisher(for: .exportResults)) { _ in
    35→            showingExportSheet = true
    36→        }
    37→    }
    38→
    39→    @ViewBuilder
    40→    private var detailView: some View {
    41→        switch selectedSidebarItem {
    42→        case .overview:
    43→            OverviewDashboardView()
    44→        case .comBr:
    45→            // NOVO: Mostrar apenas domínios .com.br
    46→            DomainsTableView(statusFilter: nil, tldFilter: ".com.br", searchText: searchText)
    47→        case .all:
    48→            DomainsTableView(statusFilter: nil, tldFilter: nil, searchText: searchText)
    49→        case .online:
    50→            DomainsTableView(statusFilter: .online, tldFilter: nil, searchText: searchText)
    51→        case .offline:
    52→            DomainsTableView(statusFilter: .offline, tldFilter: nil, searchText: searchText)
    53→        case .pending:
    54→            DomainsTableView(statusFilter: .pending, tldFilter: nil, searchText: searchText)
    55→        case .errors:
    56→            DomainsTableView(statusFilter: .error, tldFilter: nil, searchText: searchText)
    57→        case .dnsFailure:
    58→            DomainsTableView(statusFilter: .dnsFailure, tldFilter: nil, searchText: searchText)
    59→        }
    60→    }
    61→
    62→    @ToolbarContentBuilder
    63→    private var toolbarContent: some ToolbarContent {
    64→        ToolbarItemGroup(placement: .primaryAction) {
    65→            // Import Button
    66→            Button {
    67→                showingImportSheet = true
    68→            } label: {
    69→                Label("Import", systemImage: "square.and.arrow.down")
    70→            }
    71→            .help("Import domains from file (⌘I)")
    72→
    73→            Divider()
    74→
    75→            // Validation Controls
    76→            validationButtons
    77→
    78→            Divider()
    79→
    80→            // Export Button
    81→            Button {
    82→                showingExportSheet = true
    83→            } label: {
    84→                Label("Export", systemImage: "square.and.arrow.up")
    85→            }
    86→            .help("Export results (⌘E)")
    87→            .disabled(dataManager.totalDomains == 0)
    88→        }
    89→    }
    90→
    91→    @ViewBuilder
    92→    private var validationButtons: some View {
    93→        if isValidating {
    94→            if isPaused {
    95→                Button {
    96→                    resumeValidation()
    97→                } label: {
    98→                    Label("Resume", systemImage: "play.fill")
    99→                }
   100→                .help("Resume validation")
   101→
   102→                Button {
   103→                    stopValidation()
   104→                } label: {
   105→                    Label("Stop", systemImage: "stop.fill")
   106→                }
   107→                .help("Stop validation")
   108→            } else {
   109→                Button {
   110→                    pauseValidation()
   111→                } label: {
   112→                    Label("Pause", systemImage: "pause.fill")
   113→                }
   114→                .help("Pause validation (⌘.)")
   115→            }
   116→        } else {
   117→            Button {
   118→                startValidation()
   119→            } label: {
   120→                Label("Validate", systemImage: "play.fill")
   121→            }
   122→            .help("Start validation (⌘R)")
   123→            .disabled(dataManager.pendingCount == 0)
   124→        }
   125→    }
   126→
   127→    // MARK: - Actions
   128→
   129→    /// Get TLD filter based on current sidebar selection
   130→    private var currentTldFilter: String? {
   131→        switch selectedSidebarItem {
   132→        case .comBr: return ".com.br"
   133→        default: return nil
   134→        }
   135→    }
   136→
   137→    private func startValidation() {
   138→        isValidating = true
   139→        isPaused = false
   140→
   141→        Task {
   142→            // MODIFICADO: Respeitar filtro TLD da aba selecionada
   143→            let tldFilter = currentTldFilter
   144→            let pendingDomains = await dataManager.getPendingDomains(tld: tldFilter, limit: 100000)
   145→
   146→            if pendingDomains.isEmpty {
   147→                isValidating = false
   148→                return
   149→            }
   150→
   151→            print("🚀 Iniciando validação de \(pendingDomains.count) domínios\(tldFilter != nil ? " (\(tldFilter!))" : "")")
   152→
   153→            await DomainValidator.shared.startValidation(
   154→                domains: pendingDomains,
   155→                onProgress: { progress in
   156→                    dataManager.validationProgress = progress
   157→                },
   158→                onResult: { entity, result in
   159→                    dataManager.updateDomainResult(entity, with: result)
   160→
   161→                    // Incremental save every 100 domains
   162→                    if dataManager.processedDomains % 100 == 0 {
   163→                        dataManager.incrementalSave()
   164→                    }
   165→                }
   166→            )
   167→
   168→            dataManager.incrementalSave()
   169→            dataManager.updateComBrCount()  // Atualizar contagem após validação
   170→            isValidating = false
   171→        }
   172→    }
   173→
   174→    private func pauseValidation() {
   175→        Task {
   176→            await DomainValidator.shared.pause()
   177→            isPaused = true
   178→        }
   179→    }
   180→
   181→    private func resumeValidation() {
   182→        Task {
   183→            await DomainValidator.shared.resume()
   184→            isPaused = false
   185→        }
   186→    }
   187→
   188→    private func stopValidation() {
   189→        Task {
   190→            await DomainValidator.shared.stop()
   191→            isValidating = false
   192→            isPaused = false
   193→            dataManager.incrementalSave()
   194→        }
   195→    }
   196→}
   197→
   198→// MARK: - Sidebar Item
   199→
   200→enum SidebarItem: String, CaseIterable, Identifiable {
   201→    case overview = "Overview"
   202→    case comBr = ".com.br"          // NOVO: Domínios brasileiros
   203→    case all = "All Domains"
   204→    case online = "Online"
   205→    case offline = "Offline"
   206→    case pending = "Pending"
   207→    case errors = "Errors"
   208→    case dnsFailure = "DNS Failed"
   209→
   210→    var id: String { rawValue }
   211→
   212→    var icon: String {
   213→        switch self {
   214→        case .overview: return "chart.bar.fill"
   215→        case .comBr: return "flag.fill"  // Bandeira BR
   216→        case .all: return "list.bullet"
   217→        case .online: return "checkmark.circle.fill"
   218→        case .offline: return "xmark.circle.fill"
   219→        case .pending: return "clock.fill"
   220→        case .errors: return "exclamationmark.triangle.fill"
   221→        case .dnsFailure: return "network.slash"
   222→        }
   223→    }
   224→
   225→    var color: Color {
   226→        switch self {
   227→        case .overview: return .blue
   228→        case .comBr: return .green  // Verde do Brasil
   229→        case .all: return .primary
   230→        case .online: return .green
   231→        case .offline: return .red
   232→        case .pending: return .orange
   233→        case .errors: return .purple
   234→        case .dnsFailure: return .pink
   235→        }
   236→    }
   237→}
   238→
   239→#Preview {
   240→    ContentView()
   241→        .environmentObject(DataManager.shared)
   242→}
   243→

<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

struct ContentView: View {
    @EnvironmentObject var dataManager: DataManager

    @State private var selectedSidebarItem: SidebarItem = .overview
    @State private var searchText = ""
    @State private var isImporting = false
    @State private var isExporting = false
    @State private var isValidating = false
    @State private var isPaused = false
    @State private var showingImportSheet = false
    @State private var showingExportSheet = false

    var body: some View {
        NavigationSplitView {
            SidebarView(selection: $selectedSidebarItem)
        } detail: {
            detailView
                .searchable(text: $searchText, prompt: "Search domains...")
        }
        .toolbar {
            toolbarContent
        }
        .sheet(isPresented: $showingImportSheet) {
            ImportView()
        }
        .sheet(isPresented: $showingExportSheet) {
            ExportOptionsView()
        }
        .onReceive(NotificationCenter.default.publisher(for: .importDomains)) { _ in
            showingImportSheet = true
        }
        .onReceive(NotificationCenter.default.publisher(for: .exportResults)) { _ in
            showingExportSheet = true
        }
    }

    @ViewBuilder
    private var detailView: some View {
        switch selectedSidebarItem {
        case .overview:
            OverviewDashboardView()
        case .comBr:
            // NOVO: Mostrar apenas domínios .com.br
            DomainsTableView(statusFilter: nil, tldFilter: ".com.br", searchText: searchText)
        case .all:
            DomainsTableView(statusFilter: nil, tldFilter: nil, searchText: searchText)
        case .online:
            DomainsTableView(statusFilter: .online, tldFilter: nil, searchText: searchText)
        case .offline:
            DomainsTableView(statusFilter: .offline, tldFilter: nil, searchText: searchText)
        case .pending:
            DomainsTableView(statusFilter: .pending, tldFilter: nil, searchText: searchText)
        case .errors:
            DomainsTableView(statusFilter: .error, tldFilter: nil, searchText: searchText)
        case .dnsFailure:
            DomainsTableView(statusFilter: .dnsFailure, tldFilter: nil, searchText: searchText)
        }
    }

    @ToolbarContentBuilder
    private var toolbarContent: some ToolbarContent {
        ToolbarItemGroup(placement: .primaryAction) {
            // Import Button
            Button {
                showingImportSheet = true
            } label: {
                Label("Import", systemImage: "square.and.arrow.down")
            }
            .help("Import domains from file (⌘I)")

            Divider()

            // Validation Controls
            validationButtons

            Divider()

            // Export Button
            Button {
                showingExportSheet = true
            } label: {
                Label("Export", systemImage: "square.and.arrow.up")
            }
            .help("Export results (⌘E)")
            .disabled(dataManager.totalDomains == 0)
        }
    }

    @ViewBuilder
    private var validationButtons: some View {
        if isValidating {
            if isPaused {
                Button {
                    resumeValidation()
                } label: {
                    Label("Resume", systemImage: "play.fill")
                }
                .help("Resume validation")

                Button {
                    stopValidation()
                } label: {
                    Label("Stop", systemImage: "stop.fill")
                }
                .help("Stop validation")
            } else {
                Button {
                    pauseValidation()
                } label: {
                    Label("Pause", systemImage: "pause.fill")
                }
                .help("Pause validation (⌘.)")
            }
        } else {
            Button {
                startValidation()
            } label: {
                Label("Validate", systemImage: "play.fill")
            }
            .help("Start validation (⌘R)")
            .disabled(dataManager.pendingCount == 0)
        }
    }

    // MARK: - Actions

    /// Get TLD filter based on current sidebar selection
    private var currentTldFilter: String? {
        switch selectedSidebarItem {
        case .comBr: return ".com.br"
        default: return nil
        }
    }

    private func startValidation() {
        isValidating = true
        isPaused = false

        Task {
            // MODIFICADO: Respeitar filtro TLD da aba selecionada
            let tldFilter = currentTldFilter
            let pendingDomains = await dataManager.getPendingDomains(tld: tldFilter, limit: 100000)

            if pendingDomains.isEmpty {
                isValidating = false
                return
            }

            print("🚀 Iniciando validação de \(pendingDomains.count) domínios\(tldFilter != nil ? " (\(tldFilter!))" : "")")

            await DomainValidator.shared.startValidation(
                domains: pendingDomains,
                onProgress: { progress in
                    dataManager.validationProgress = progress
                },
                onResult: { entity, result in
                    dataManager.updateDomainResult(entity, with: result)

                    // Incremental save every 100 domains
                    if dataManager.processedDomains % 100 == 0 {
                        dataManager.incrementalSave()
                    }
                }
            )

            dataManager.incrementalSave()
            dataManager.updateComBrCount()  // Atualizar contagem após validação
            isValidating = false
        }
    }

    private func pauseValidation() {
        Task {
            await DomainValidator.shared.pause()
            isPaused = true
        }
    }

    private func resumeValidation() {
        Task {
            await DomainValidator.shared.resume()
            isPaused = false
        }
    }

    private func stopValidation() {
        Task {
            await DomainValidator.shared.stop()
            isValidating = false
            isPaused = false
            dataManager.incrementalSave()
        }
    }
}

// MARK: - Sidebar Item

enum SidebarItem: String, CaseIterable, Identifiable {
    case overview = "Overview"
    case comBr = ".com.br"          // NOVO: Domínios brasileiros
    case all = "All Domains"
    case online = "Online"
    case offline = "Offline"
    case pending = "Pending"
    case errors = "Errors"
    case dnsFailure = "DNS Failed"

    var id: String { rawValue }

    var icon: String {
        switch self {
        case .overview: return "chart.bar.fill"
        case .comBr: return "flag.fill"  // Bandeira BR
        case .all: return "list.bullet"
        case .online: return "checkmark.circle.fill"
        case .offline: return "xmark.circle.fill"
        case .pending: return "clock.fill"
        case .errors: return "exclamationmark.triangle.fill"
        case .dnsFailure: return "network.slash"
        }
    }

    var color: Color {
        switch self {
        case .overview: return .blue
        case .comBr: return .green  // Verde do Brasil
        case .all: return .primary
        case .online: return .green
        case .offline: return .red
        case .pending: return .orange
        case .errors: return .purple
        case .dnsFailure: return .pink
        }
    }
}

#Preview {
    ContentView()
        .environmentObject(DataManager.shared)
}


     1→import Foundation
     2→
     3→/// Manages validation session state for pause/resume functionality
     4→class SessionManager {
     5→    static let shared = SessionManager()
     6→
     7→    private let userDefaults = UserDefaults.standard
     8→    private let checkpointKey = "DomainChecker_ValidationCheckpoint_v1"
     9→
    10→    // MARK: - Checkpoint Model
    11→
    12→    struct ValidationCheckpoint: Codable {
    13→        let sessionID: UUID
    14→        let lastProcessedIndex: Int
    15→        let pausedAt: Date
    16→        let statistics: PartialStats
    17→
    18→        struct PartialStats: Codable {
    19→            let total: Int
    20→            let processed: Int
    21→            let online: Int
    22→            let offline: Int
    23→            let dnsFailure: Int
    24→            let timeout: Int
    25→            let error: Int
    26→        }
    27→    }
    28→
    29→    // MARK: - Save Checkpoint
    30→
    31→    func saveCheckpoint(
    32→        sessionID: UUID,
    33→        lastProcessedIndex: Int,
    34→        stats: SessionStats
    35→    ) {
    36→        let checkpoint = ValidationCheckpoint(
    37→            sessionID: sessionID,
    38→            lastProcessedIndex: lastProcessedIndex,
    39→            pausedAt: Date(),
    40→            statistics: ValidationCheckpoint.PartialStats(
    41→                total: stats.totalDomains,
    42→                processed: stats.processedDomains,
    43→                online: stats.onlineCount,
    44→                offline: stats.offlineCount,
    45→                dnsFailure: stats.dnsFailureCount,
    46→                timeout: stats.timeoutCount,
    47→                error: stats.errorCount
    48→            )
    49→        )
    50→
    51→        if let encoded = try? JSONEncoder().encode(checkpoint) {
    52→            userDefaults.set(encoded, forKey: checkpointKey)
    53→            print("Checkpoint saved: \(lastProcessedIndex) domains processed")
    54→        }
    55→    }
    56→
    57→    // MARK: - Load Checkpoint
    58→
    59→    func loadCheckpoint() -> ValidationCheckpoint? {
    60→        guard let data = userDefaults.data(forKey: checkpointKey),
    61→              let checkpoint = try? JSONDecoder().decode(ValidationCheckpoint.self, from: data) else {
    62→            return nil
    63→        }
    64→
    65→        // Check if checkpoint is still valid (less than 24 hours old)
    66→        let maxAge: TimeInterval = 24 * 60 * 60 // 24 hours
    67→        if Date().timeIntervalSince(checkpoint.pausedAt) > maxAge {
    68→            clearCheckpoint()
    69→            return nil
    70→        }
    71→
    72→        return checkpoint
    73→    }
    74→
    75→    // MARK: - Clear Checkpoint
    76→
    77→    func clearCheckpoint() {
    78→        userDefaults.removeObject(forKey: checkpointKey)
    79→        print("Checkpoint cleared")
    80→    }
    81→
    82→    // MARK: - Check for Resumable Session
    83→
    84→    func hasResumableSession(for sessionID: UUID) -> Bool {
    85→        guard let checkpoint = loadCheckpoint() else { return false }
    86→        return checkpoint.sessionID == sessionID && checkpoint.statistics.processed < checkpoint.statistics.total
    87→    }
    88→
    89→    // MARK: - Get Resume Info
    90→
    91→    func getResumeInfo() -> (sessionID: UUID, processedCount: Int, pausedAt: Date)? {
    92→        guard let checkpoint = loadCheckpoint() else { return nil }
    93→        return (checkpoint.sessionID, checkpoint.statistics.processed, checkpoint.pausedAt)
    94→    }
    95→}
    96→
    97→// MARK: - Session State Persistence
    98→
    99→extension SessionManager {
   100→    /// Auto-save interval for incremental checkpoints
   101→    static let autoSaveInterval: Int = 100 // Save every 100 domains
   102→
   103→    /// Should save checkpoint now?
   104→    func shouldSaveCheckpoint(processedCount: Int) -> Bool {
   105→        processedCount > 0 && processedCount % SessionManager.autoSaveInterval == 0
   106→    }
   107→}
   108→
   109→// MARK: - Validation State
   110→
   111→enum ValidationState: Equatable {
   112→    case idle
   113→    case running(startedAt: Date)
   114→    case paused(pausedAt: Date)
   115→    case completed(completedAt: Date)
   116→    case cancelled
   117→
   118→    var canStart: Bool {
   119→        switch self {
   120→        case .idle, .completed, .cancelled: return true
   121→        default: return false
   122→        }
   123→    }
   124→
   125→    var canPause: Bool {
   126→        if case .running = self { return true }
   127→        return false
   128→    }
   129→
   130→    var canResume: Bool {
   131→        if case .paused = self { return true }
   132→        return false
   133→    }
   134→
   135→    var isActive: Bool {
   136→        switch self {
   137→        case .running, .paused: return true
   138→        default: return false
   139→        }
   140→    }
   141→}
   142→

<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

/// Manages validation session state for pause/resume functionality
class SessionManager {
    static let shared = SessionManager()

    private let userDefaults = UserDefaults.standard
    private let checkpointKey = "DomainChecker_ValidationCheckpoint_v1"

    // MARK: - Checkpoint Model

    struct ValidationCheckpoint: Codable {
        let sessionID: UUID
        let lastProcessedIndex: Int
        let pausedAt: Date
        let statistics: PartialStats

        struct PartialStats: Codable {
            let total: Int
            let processed: Int
            let online: Int
            let offline: Int
            let dnsFailure: Int
            let timeout: Int
            let error: Int
        }
    }

    // MARK: - Save Checkpoint

    func saveCheckpoint(
        sessionID: UUID,
        lastProcessedIndex: Int,
        stats: SessionStats
    ) {
        let checkpoint = ValidationCheckpoint(
            sessionID: sessionID,
            lastProcessedIndex: lastProcessedIndex,
            pausedAt: Date(),
            statistics: ValidationCheckpoint.PartialStats(
                total: stats.totalDomains,
                processed: stats.processedDomains,
                online: stats.onlineCount,
                offline: stats.offlineCount,
                dnsFailure: stats.dnsFailureCount,
                timeout: stats.timeoutCount,
                error: stats.errorCount
            )
        )

        if let encoded = try? JSONEncoder().encode(checkpoint) {
            userDefaults.set(encoded, forKey: checkpointKey)
            print("Checkpoint saved: \(lastProcessedIndex) domains processed")
        }
    }

    // MARK: - Load Checkpoint

    func loadCheckpoint() -> ValidationCheckpoint? {
        guard let data = userDefaults.data(forKey: checkpointKey),
              let checkpoint = try? JSONDecoder().decode(ValidationCheckpoint.self, from: data) else {
            return nil
        }

        // Check if checkpoint is still valid (less than 24 hours old)
        let maxAge: TimeInterval = 24 * 60 * 60 // 24 hours
        if Date().timeIntervalSince(checkpoint.pausedAt) > maxAge {
            clearCheckpoint()
            return nil
        }

        return checkpoint
    }

    // MARK: - Clear Checkpoint

    func clearCheckpoint() {
        userDefaults.removeObject(forKey: checkpointKey)
        print("Checkpoint cleared")
    }

    // MARK: - Check for Resumable Session

    func hasResumableSession(for sessionID: UUID) -> Bool {
        guard let checkpoint = loadCheckpoint() else { return false }
        return checkpoint.sessionID == sessionID && checkpoint.statistics.processed < checkpoint.statistics.total
    }

    // MARK: - Get Resume Info

    func getResumeInfo() -> (sessionID: UUID, processedCount: Int, pausedAt: Date)? {
        guard let checkpoint = loadCheckpoint() else { return nil }
        return (checkpoint.sessionID, checkpoint.statistics.processed, checkpoint.pausedAt)
    }
}

// MARK: - Session State Persistence

extension SessionManager {
    /// Auto-save interval for incremental checkpoints
    static let autoSaveInterval: Int = 100 // Save every 100 domains

    /// Should save checkpoint now?
    func shouldSaveCheckpoint(processedCount: Int) -> Bool {
        processedCount > 0 && processedCount % SessionManager.autoSaveInterval == 0
    }
}

// MARK: - Validation State

enum ValidationState: Equatable {
    case idle
    case running(startedAt: Date)
    case paused(pausedAt: Date)
    case completed(completedAt: Date)
    case cancelled

    var canStart: Bool {
        switch self {
        case .idle, .completed, .cancelled: return true
        default: return false
        }
    }

    var canPause: Bool {
        if case .running = self { return true }
        return false
    }

    var canResume: Bool {
        if case .paused = self { return true }
        return false
    }

    var isActive: Bool {
        switch self {
        case .running, .paused: return true
        default: return false
        }
    }
}


     1→import Foundation
     2→import CoreData
     3→import SwiftUI
     4→
     5→/// Main data manager for CoreData operations
     6→@MainActor
     7→class DataManager: ObservableObject {
     8→    static let shared = DataManager()
     9→
    10→    // MARK: - Published Properties
    11→
    12→    @Published var currentSession: ValidationSessionEntity?
    13→    @Published var sessions: [ValidationSessionEntity] = []
    14→    @Published var isImporting = false
    15→    @Published var importProgress: Double = 0
    16→    @Published var validationProgress: ValidationProgress?
    17→
    18→    // MARK: - Statistics (computed from session)
    19→
    20→    var totalDomains: Int { Int(currentSession?.totalDomains ?? 0) }
    21→    var processedDomains: Int { Int(currentSession?.processedDomains ?? 0) }
    22→    var onlineCount: Int { Int(currentSession?.onlineCount ?? 0) }
    23→    var offlineCount: Int { Int(currentSession?.offlineCount ?? 0) }
    24→    var pendingCount: Int { totalDomains - processedDomains }
    25→    var errorCount: Int { Int(currentSession?.errorCount ?? 0) }
    26→    var dnsFailureCount: Int { Int(currentSession?.dnsFailureCount ?? 0) }
    27→
    28→    // MARK: - TLD Statistics (query-based)
    29→
    30→    @Published private(set) var comBrCount: Int = 0
    31→
    32→    func updateComBrCount() {
    33→        let request = NSFetchRequest<NSNumber>(entityName: "DomainEntity")
    34→        request.resultType = .countResultType
    35→        request.predicate = NSPredicate(format: "tld == %@", ".com.br")
    36→
    37→        do {
    38→            let count = try viewContext.count(for: request as! NSFetchRequest<NSFetchRequestResult>)
    39→            comBrCount = count
    40→        } catch {
    41→            print("Error counting .com.br domains: \(error)")
    42→            comBrCount = 0
    43→        }
    44→    }
    45→
    46→    // MARK: - CoreData Stack
    47→
    48→    private let persistentContainer: NSPersistentContainer
    49→
    50→    var viewContext: NSManagedObjectContext {
    51→        persistentContainer.viewContext
    52→    }
    53→
    54→    func newBackgroundContext() -> NSManagedObjectContext {
    55→        let context = persistentContainer.newBackgroundContext()
    56→        context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    57→        context.automaticallyMergesChangesFromParent = true
    58→        return context
    59→    }
    60→
    61→    // MARK: - Initialization
    62→
    63→    private init() {
    64→        // Create container with programmatic model
    65→        let model = CoreDataModelBuilder.createModel()
    66→        persistentContainer = NSPersistentContainer(name: "DomainChecker", managedObjectModel: model)
    67→
    68→        // Configure persistent store
    69→        let storeURL = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
    70→            .first!
    71→            .appendingPathComponent("DomainChecker")
    72→            .appendingPathComponent("DomainChecker.sqlite")
    73→
    74→        // Create directory if needed
    75→        let storeDir = storeURL.deletingLastPathComponent()
    76→        try? FileManager.default.createDirectory(at: storeDir, withIntermediateDirectories: true)
    77→
    78→        let description = NSPersistentStoreDescription(url: storeURL)
    79→        description.shouldMigrateStoreAutomatically = true
    80→        description.shouldInferMappingModelAutomatically = true
    81→
    82→        persistentContainer.persistentStoreDescriptions = [description]
    83→
    84→        persistentContainer.loadPersistentStores { description, error in
    85→            if let error = error {
    86→                print("CoreData error: \(error.localizedDescription)")
    87→            } else {
    88→                print("CoreData loaded: \(description.url?.path ?? "unknown")")
    89→            }
    90→        }
    91→
    92→        viewContext.automaticallyMergesChangesFromParent = true
    93→        viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    94→
    95→        // Load sessions
    96→        Task {
    97→            await loadSessions()
    98→        }
    99→    }
   100→
   101→    // MARK: - Session Management
   102→
   103→    func loadSessions() async {
   104→        let request = ValidationSessionEntity.fetchRequest()
   105→        request.sortDescriptors = [NSSortDescriptor(key: "updatedAt", ascending: false)]
   106→
   107→        do {
   108→            sessions = try viewContext.fetch(request)
   109→            if currentSession == nil {
   110→                currentSession = sessions.first
   111→            }
   112→        } catch {
   113→            print("Error loading sessions: \(error)")
   114→        }
   115→    }
   116→
   117→    func createSession(name: String, sourceFile: URL, domainCount: Int) -> ValidationSessionEntity {
   118→        let session = ValidationSessionEntity(context: viewContext)
   119→        session.id = UUID()
   120→        session.name = name.isEmpty ? "Session \(Date().formatted(date: .abbreviated, time: .shortened))" : name
   121→        session.createdAt = Date()
   122→        session.updatedAt = Date()
   123→        session.sourceFileName = sourceFile.lastPathComponent
   124→        session.sourceFilePath = sourceFile.path
   125→        session.totalDomains = Int32(domainCount)
   126→        session.processedDomains = 0
   127→        session.onlineCount = 0
   128→        session.offlineCount = 0
   129→        session.dnsFailureCount = 0
   130→        session.timeoutCount = 0
   131→        session.errorCount = 0
   132→        session.status = "pending"
   133→
   134→        saveContext()
   135→
   136→        currentSession = session
   137→        sessions.insert(session, at: 0)
   138→
   139→        return session
   140→    }
   141→
   142→    func deleteSession(_ session: ValidationSessionEntity) async {
   143→        let context = newBackgroundContext()
   144→
   145→        await context.perform {
   146→            // Delete all domains for this session
   147→            let domainRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "DomainEntity")
   148→            domainRequest.predicate = NSPredicate(format: "session == %@", session)
   149→            let deleteRequest = NSBatchDeleteRequest(fetchRequest: domainRequest)
   150→
   151→            do {
   152→                try context.execute(deleteRequest)
   153→
   154→                // Delete session
   155→                if let sessionToDelete = try context.existingObject(with: session.objectID) as? ValidationSessionEntity {
   156→                    context.delete(sessionToDelete)
   157→                }
   158→
   159→                try context.save()
   160→            } catch {
   161→                print("Error deleting session: \(error)")
   162→            }
   163→        }
   164→
   165→        await MainActor.run {
   166→            sessions.removeAll { $0.id == session.id }
   167→            if currentSession?.id == session.id {
   168→                currentSession = sessions.first
   169→            }
   170→        }
   171→    }
   172→
   173→    // MARK: - Domain Import
   174→
   175→    func importDomains(from fileURL: URL, sessionName: String) async -> Int {
   176→        await MainActor.run {
   177→            isImporting = true
   178→            importProgress = 0
   179→        }
   180→
   181→        // Read and parse file on background thread
   182→        let fileContent: String
   183→        do {
   184→            fileContent = try String(contentsOf: fileURL, encoding: .utf8)
   185→        } catch {
   186→            print("Import error reading file: \(error)")
   187→            await MainActor.run {
   188→                isImporting = false
   189→            }
   190→            return 0
   191→        }
   192→
   193→        let lines = fileContent.components(separatedBy: .newlines)
   194→
   195→        // Parse and clean domains
   196→        var domains: [(line: Int, domain: String)] = []
   197→        for (index, line) in lines.enumerated() {
   198→            let cleaned = cleanDomain(line)
   199→            if !cleaned.isEmpty {
   200→                domains.append((index + 1, cleaned))
   201→            }
   202→        }
   203→
   204→        let totalDomains = domains.count
   205→
   206→        // Create session on main context
   207→        _ = await MainActor.run {
   208→            createSession(name: sessionName, sourceFile: fileURL, domainCount: totalDomains)
   209→        }
   210→
   211→        // Batch insert domains on background context
   212→        let context = newBackgroundContext()
   213→        var importedCount = 0
   214→        let batchSize = 1000
   215→
   216→        for batchStart in stride(from: 0, to: domains.count, by: batchSize) {
   217→            let batchEnd = min(batchStart + batchSize, domains.count)
   218→            let batch = Array(domains[batchStart..<batchEnd])
   219→
   220→            context.performAndWait {
   221→                for (lineNumber, domain) in batch {
   222→                    let entity = DomainEntity(context: context)
   223→                    entity.id = UUID()
   224→                    entity.domain = domain
   225→                    entity.status = "pending"
   226→                    entity.importedAt = Date()
   227→                    entity.lineNumber = Int32(lineNumber)
   228→                    entity.tld = extractTLD(from: domain)
   229→                    entity.retryCount = 0
   230→                }
   231→
   232→                do {
   233→                    try context.save()
   234→                    importedCount += batch.count
   235→                } catch {
   236→                    print("Import batch save error: \(error)")
   237→                }
   238→            }
   239→
   240→            // Update progress on main actor
   241→            let progress = Double(batchStart + batch.count) / Double(totalDomains)
   242→            await MainActor.run {
   243→                self.importProgress = progress
   244→            }
   245→        }
   246→
   247→        await MainActor.run {
   248→            isImporting = false
   249→            importProgress = 1.0
   250→        }
   251→
   252→        await loadSessions()
   253→        updateComBrCount()  // Atualizar contagem de domínios .com.br
   254→        return importedCount
   255→    }
   256→
   257→    // MARK: - Domain Queries
   258→
   259→    func fetchDomains(
   260→        status: DomainStatus? = nil,
   261→        tld: String? = nil,
   262→        searchText: String = "",
   263→        limit: Int = 1000,
   264→        offset: Int = 0
   265→    ) async -> [DomainEntity] {
   266→        let request = DomainEntity.fetchRequest()
   267→
   268→        var predicates: [NSPredicate] = []
   269→
   270→        if let session = currentSession {
   271→            predicates.append(NSPredicate(format: "session == %@", session))
   272→        }
   273→
   274→        if let status = status {
   275→            predicates.append(NSPredicate(format: "status == %@", status.rawValue))
   276→        }
   277→
   278→        // NOVO: Filtro por TLD (ex: ".com.br")
   279→        if let tld = tld {
   280→            predicates.append(NSPredicate(format: "tld == %@", tld))
   281→        }
   282→
   283→        if !searchText.isEmpty {
   284→            predicates.append(NSPredicate(format: "domain CONTAINS[cd] %@", searchText))
   285→        }
   286→
   287→        if !predicates.isEmpty {
   288→            request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
   289→        }
   290→
   291→        request.sortDescriptors = [NSSortDescriptor(key: "lineNumber", ascending: true)]
   292→        request.fetchLimit = limit
   293→        request.fetchOffset = offset
   294→        request.fetchBatchSize = 100
   295→
   296→        return (try? viewContext.fetch(request)) ?? []
   297→    }
   298→
   299→    func getPendingDomains(tld: String? = nil, limit: Int = 10000) async -> [DomainEntity] {
   300→        return await fetchDomains(status: .pending, tld: tld, limit: limit)
   301→    }
   302→
   303→    func getStatusCounts() async -> [DomainStatus: Int] {
   304→        let context = newBackgroundContext()
   305→
   306→        return await context.perform {
   307→            var counts: [DomainStatus: Int] = [:]
   308→
   309→            for status in DomainStatus.allCases {
   310→                let request = NSFetchRequest<NSNumber>(entityName: "DomainEntity")
   311→                request.resultType = .countResultType
   312→                request.predicate = NSPredicate(format: "status == %@", status.rawValue)
   313→
   314→                counts[status] = (try? context.count(for: request)) ?? 0
   315→            }
   316→
   317→            return counts
   318→        }
   319→    }
   320→
   321→    // MARK: - Update Domain Result
   322→
   323→    func updateDomainResult(_ domain: DomainEntity, with result: DomainResult) {
   324→        domain.update(from: result)
   325→
   326→        // Update session counts
   327→        if let session = currentSession {
   328→            session.processedDomains += 1
   329→
   330→            switch result.status {
   331→            case .online:
   332→                session.onlineCount += 1
   333→            case .offline:
   334→                session.offlineCount += 1
   335→            case .dnsFailure:
   336→                session.dnsFailureCount += 1
   337→            case .timeout:
   338→                session.timeoutCount += 1
   339→            case .error:
   340→                session.errorCount += 1
   341→            case .pending:
   342→                break
   343→            }
   344→
   345→            session.updatedAt = Date()
   346→            session.lastProcessedDomain = domain.domain
   347→        }
   348→    }
   349→
   350→    func incrementalSave() {
   351→        if viewContext.hasChanges {
   352→            try? viewContext.save()
   353→        }
   354→    }
   355→
   356→    // MARK: - Helpers
   357→
   358→    nonisolated private func cleanDomain(_ input: String) -> String {
   359→        var domain = input.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
   360→
   361→        // NOVO: Extrair domínio de email (tudo depois do @)
   362→        if domain.contains("@") {
   363→            let parts = domain.components(separatedBy: "@")
   364→            if parts.count == 2 && !parts[1].isEmpty {
   365→                domain = parts[1]  // Pega apenas o domínio do email
   366→            } else {
   367→                return ""  // Email inválido
   368→            }
   369→        }
   370→
   371→        // Remove protocol
   372→        if domain.hasPrefix("https://") {
   373→            domain = String(domain.dropFirst(8))
   374→        } else if domain.hasPrefix("http://") {
   375→            domain = String(domain.dropFirst(7))
   376→        }
   377→
   378→        // Remove path
   379→        if let slashIndex = domain.firstIndex(of: "/") {
   380→            domain = String(domain[..<slashIndex])
   381→        }
   382→
   383→        // Remove port
   384→        if let colonIndex = domain.firstIndex(of: ":") {
   385→            domain = String(domain[..<colonIndex])
   386→        }
   387→
   388→        // Remove www prefix
   389→        if domain.hasPrefix("www.") {
   390→            domain = String(domain.dropFirst(4))
   391→        }
   392→
   393→        // Basic validation
   394→        guard domain.contains("."),
   395→              domain.count >= 4,
   396→              !domain.contains(" ") else {
   397→            return ""
   398→        }
   399→
   400→        return domain
   401→    }
   402→
   403→    nonisolated private func extractTLD(from domain: String) -> String {
   404→        let parts = domain.components(separatedBy: ".")
   405→        guard parts.count >= 2 else { return "" }
   406→
   407→        // Handle common multi-part TLDs
   408→        let lastTwo = parts.suffix(2).joined(separator: ".")
   409→        let multiPartTLDs = ["com.br", "co.uk", "com.au", "co.nz", "co.jp", "com.mx"]
   410→
   411→        if multiPartTLDs.contains(lastTwo) {
   412→            return ".\(lastTwo)"
   413→        }
   414→
   415→        return ".\(parts.last ?? "")"
   416→    }
   417→
   418→    func saveContext() {
   419→        if viewContext.hasChanges {
   420→            do {
   421→                try viewContext.save()
   422→            } catch {
   423→                print("Error saving context: \(error)")
   424→            }
   425→        }
   426→    }
   427→}
   428→

<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
import CoreData
import SwiftUI

/// Main data manager for CoreData operations
@MainActor
class DataManager: ObservableObject {
    static let shared = DataManager()

    // MARK: - Published Properties

    @Published var currentSession: ValidationSessionEntity?
    @Published var sessions: [ValidationSessionEntity] = []
    @Published var isImporting = false
    @Published var importProgress: Double = 0
    @Published var validationProgress: ValidationProgress?

    // MARK: - Statistics (computed from session)

    var totalDomains: Int { Int(currentSession?.totalDomains ?? 0) }
    var processedDomains: Int { Int(currentSession?.processedDomains ?? 0) }
    var onlineCount: Int { Int(currentSession?.onlineCount ?? 0) }
    var offlineCount: Int { Int(currentSession?.offlineCount ?? 0) }
    var pendingCount: Int { totalDomains - processedDomains }
    var errorCount: Int { Int(currentSession?.errorCount ?? 0) }
    var dnsFailureCount: Int { Int(currentSession?.dnsFailureCount ?? 0) }

    // MARK: - TLD Statistics (query-based)

    @Published private(set) var comBrCount: Int = 0

    func updateComBrCount() {
        let request = NSFetchRequest<NSNumber>(entityName: "DomainEntity")
        request.resultType = .countResultType
        request.predicate = NSPredicate(format: "tld == %@", ".com.br")

        do {
            let count = try viewContext.count(for: request as! NSFetchRequest<NSFetchRequestResult>)
            comBrCount = count
        } catch {
            print("Error counting .com.br domains: \(error)")
            comBrCount = 0
        }
    }

    // MARK: - CoreData Stack

    private let persistentContainer: NSPersistentContainer

    var viewContext: NSManagedObjectContext {
        persistentContainer.viewContext
    }

    func newBackgroundContext() -> NSManagedObjectContext {
        let context = persistentContainer.newBackgroundContext()
        context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        context.automaticallyMergesChangesFromParent = true
        return context
    }

    // MARK: - Initialization

    private init() {
        // Create container with programmatic model
        let model = CoreDataModelBuilder.createModel()
        persistentContainer = NSPersistentContainer(name: "DomainChecker", managedObjectModel: model)

        // Configure persistent store
        let storeURL = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
            .first!
            .appendingPathComponent("DomainChecker")
            .appendingPathComponent("DomainChecker.sqlite")

        // Create directory if needed
        let storeDir = storeURL.deletingLastPathComponent()
        try? FileManager.default.createDirectory(at: storeDir, withIntermediateDirectories: true)

        let description = NSPersistentStoreDescription(url: storeURL)
        description.shouldMigrateStoreAutomatically = true
        description.shouldInferMappingModelAutomatically = true

        persistentContainer.persistentStoreDescriptions = [description]

        persistentContainer.loadPersistentStores { description, error in
            if let error = error {
                print("CoreData error: \(error.localizedDescription)")
            } else {
                print("CoreData loaded: \(description.url?.path ?? "unknown")")
            }
        }

        viewContext.automaticallyMergesChangesFromParent = true
        viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

        // Load sessions
        Task {
            await loadSessions()
        }
    }

    // MARK: - Session Management

    func loadSessions() async {
        let request = ValidationSessionEntity.fetchRequest()
        request.sortDescriptors = [NSSortDescriptor(key: "updatedAt", ascending: false)]

        do {
            sessions = try viewContext.fetch(request)
            if currentSession == nil {
                currentSession = sessions.first
            }
        } catch {
            print("Error loading sessions: \(error)")
        }
    }

    func createSession(name: String, sourceFile: URL, domainCount: Int) -> ValidationSessionEntity {
        let session = ValidationSessionEntity(context: viewContext)
        session.id = UUID()
        session.name = name.isEmpty ? "Session \(Date().formatted(date: .abbreviated, time: .shortened))" : name
        session.createdAt = Date()
        session.updatedAt = Date()
        session.sourceFileName = sourceFile.lastPathComponent
        session.sourceFilePath = sourceFile.path
        session.totalDomains = Int32(domainCount)
        session.processedDomains = 0
        session.onlineCount = 0
        session.offlineCount = 0
        session.dnsFailureCount = 0
        session.timeoutCount = 0
        session.errorCount = 0
        session.status = "pending"

        saveContext()

        currentSession = session
        sessions.insert(session, at: 0)

        return session
    }

    func deleteSession(_ session: ValidationSessionEntity) async {
        let context = newBackgroundContext()

        await context.perform {
            // Delete all domains for this session
            let domainRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "DomainEntity")
            domainRequest.predicate = NSPredicate(format: "session == %@", session)
            let deleteRequest = NSBatchDeleteRequest(fetchRequest: domainRequest)

            do {
                try context.execute(deleteRequest)

                // Delete session
                if let sessionToDelete = try context.existingObject(with: session.objectID) as? ValidationSessionEntity {
                    context.delete(sessionToDelete)
                }

                try context.save()
            } catch {
                print("Error deleting session: \(error)")
            }
        }

        await MainActor.run {
            sessions.removeAll { $0.id == session.id }
            if currentSession?.id == session.id {
                currentSession = sessions.first
            }
        }
    }

    // MARK: - Domain Import

    func importDomains(from fileURL: URL, sessionName: String) async -> Int {
        await MainActor.run {
            isImporting = true
            importProgress = 0
        }

        // Read and parse file on background thread
        let fileContent: String
        do {
            fileContent = try String(contentsOf: fileURL, encoding: .utf8)
        } catch {
            print("Import error reading file: \(error)")
            await MainActor.run {
                isImporting = false
            }
            return 0
        }

        let lines = fileContent.components(separatedBy: .newlines)

        // Parse and clean domains
        var domains: [(line: Int, domain: String)] = []
        for (index, line) in lines.enumerated() {
            let cleaned = cleanDomain(line)
            if !cleaned.isEmpty {
                domains.append((index + 1, cleaned))
            }
        }

        let totalDomains = domains.count

        // Create session on main context
        _ = await MainActor.run {
            createSession(name: sessionName, sourceFile: fileURL, domainCount: totalDomains)
        }

        // Batch insert domains on background context
        let context = newBackgroundContext()
        var importedCount = 0
        let batchSize = 1000

        for batchStart in stride(from: 0, to: domains.count, by: batchSize) {
            let batchEnd = min(batchStart + batchSize, domains.count)
            let batch = Array(domains[batchStart..<batchEnd])

            context.performAndWait {
                for (lineNumber, domain) in batch {
                    let entity = DomainEntity(context: context)
                    entity.id = UUID()
                    entity.domain = domain
                    entity.status = "pending"
                    entity.importedAt = Date()
                    entity.lineNumber = Int32(lineNumber)
                    entity.tld = extractTLD(from: domain)
                    entity.retryCount = 0
                }

                do {
                    try context.save()
                    importedCount += batch.count
                } catch {
                    print("Import batch save error: \(error)")
                }
            }

            // Update progress on main actor
            let progress = Double(batchStart + batch.count) / Double(totalDomains)
            await MainActor.run {
                self.importProgress = progress
            }
        }

        await MainActor.run {
            isImporting = false
            importProgress = 1.0
        }

        await loadSessions()
        updateComBrCount()  // Atualizar contagem de domínios .com.br
        return importedCount
    }

    // MARK: - Domain Queries

    func fetchDomains(
        status: DomainStatus? = nil,
        tld: String? = nil,
        searchText: String = "",
        limit: Int = 1000,
        offset: Int = 0
    ) async -> [DomainEntity] {
        let request = DomainEntity.fetchRequest()

        var predicates: [NSPredicate] = []

        if let session = currentSession {
            predicates.append(NSPredicate(format: "session == %@", session))
        }

        if let status = status {
            predicates.append(NSPredicate(format: "status == %@", status.rawValue))
        }

        // NOVO: Filtro por TLD (ex: ".com.br")
        if let tld = tld {
            predicates.append(NSPredicate(format: "tld == %@", tld))
        }

        if !searchText.isEmpty {
            predicates.append(NSPredicate(format: "domain CONTAINS[cd] %@", searchText))
        }

        if !predicates.isEmpty {
            request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
        }

        request.sortDescriptors = [NSSortDescriptor(key: "lineNumber", ascending: true)]
        request.fetchLimit = limit
        request.fetchOffset = offset
        request.fetchBatchSize = 100

        return (try? viewContext.fetch(request)) ?? []
    }

    func getPendingDomains(tld: String? = nil, limit: Int = 10000) async -> [DomainEntity] {
        return await fetchDomains(status: .pending, tld: tld, limit: limit)
    }

    func getStatusCounts() async -> [DomainStatus: Int] {
        let context = newBackgroundContext()

        return await context.perform {
            var counts: [DomainStatus: Int] = [:]

            for status in DomainStatus.allCases {
                let request = NSFetchRequest<NSNumber>(entityName: "DomainEntity")
                request.resultType = .countResultType
                request.predicate = NSPredicate(format: "status == %@", status.rawValue)

                counts[status] = (try? context.count(for: request)) ?? 0
            }

            return counts
        }
    }

    // MARK: - Update Domain Result

    func updateDomainResult(_ domain: DomainEntity, with result: DomainResult) {
        domain.update(from: result)

        // Update session counts
        if let session = currentSession {
            session.processedDomains += 1

            switch result.status {
            case .online:
                session.onlineCount += 1
            case .offline:
                session.offlineCount += 1
            case .dnsFailure:
                session.dnsFailureCount += 1
            case .timeout:
                session.timeoutCount += 1
            case .error:
                session.errorCount += 1
            case .pending:
                break
            }

            session.updatedAt = Date()
            session.lastProcessedDomain = domain.domain
        }
    }

    func incrementalSave() {
        if viewContext.hasChanges {
            try? viewContext.save()
        }
    }

    // MARK: - Helpers

    nonisolated private func cleanDomain(_ input: String) -> String {
        var domain = input.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()

        // NOVO: Extrair domínio de email (tudo depois do @)
        if domain.contains("@") {
            let parts = domain.components(separatedBy: "@")
            if parts.count == 2 && !parts[1].isEmpty {
                domain = parts[1]  // Pega apenas o domínio do email
            } else {
                return ""  // Email inválido
            }
        }

        // Remove protocol
        if domain.hasPrefix("https://") {
            domain = String(domain.dropFirst(8))
        } else if domain.hasPrefix("http://") {
            domain = String(domain.dropFirst(7))
        }

        // Remove path
        if let slashIndex = domain.firstIndex(of: "/") {
            domain = String(domain[..<slashIndex])
        }

        // Remove port
        if let colonIndex = domain.firstIndex(of: ":") {
            domain = String(domain[..<colonIndex])
        }

        // Remove www prefix
        if domain.hasPrefix("www.") {
            domain = String(domain.dropFirst(4))
        }

        // Basic validation
        guard domain.contains("."),
              domain.count >= 4,
              !domain.contains(" ") else {
            return ""
        }

        return domain
    }

    nonisolated private func extractTLD(from domain: String) -> String {
        let parts = domain.components(separatedBy: ".")
        guard parts.count >= 2 else { return "" }

        // Handle common multi-part TLDs
        let lastTwo = parts.suffix(2).joined(separator: ".")
        let multiPartTLDs = ["com.br", "co.uk", "com.au", "co.nz", "co.jp", "com.mx"]

        if multiPartTLDs.contains(lastTwo) {
            return ".\(lastTwo)"
        }

        return ".\(parts.last ?? "")"
    }

    func saveContext() {
        if viewContext.hasChanges {
            do {
                try viewContext.save()
            } catch {
                print("Error saving context: \(error)")
            }
        }
    }
}


Now let me explore the Overview dashboard and additional UI components to understand the full architecture:


     1→import SwiftUI
     2→
     3→struct OverviewDashboardView: View {
     4→    @EnvironmentObject var dataManager: DataManager
     5→
     6→    var body: some View {
     7→        ScrollView {
     8→            VStack(spacing: 24) {
     9→                // Stats Cards
    10→                statsCardsSection
    11→
    12→                // Progress Section (when validating)
    13→                if let progress = dataManager.validationProgress {
    14→                    ValidationProgressView(progress: progress)
    15→                        .padding()
    16→                        .background(Color(nsColor: .windowBackgroundColor))
    17→                        .clipShape(RoundedRectangle(cornerRadius: 16))
    18→                }
    19→
    20→                // Distribution Chart
    21→                if dataManager.totalDomains > 0 {
    22→                    distributionSection
    23→                }
    24→
    25→                // Session Info
    26→                if let session = dataManager.currentSession {
    27→                    sessionInfoSection(session)
    28→                }
    29→
    30→                Spacer()
    31→            }
    32→            .padding()
    33→        }
    34→        .navigationTitle("Overview")
    35→        .background(Color(nsColor: .controlBackgroundColor))
    36→    }
    37→
    38→    // MARK: - Stats Cards
    39→
    40→    private var statsCardsSection: some View {
    41→        VStack(spacing: 16) {
    42→            // Linha 1: Principais
    43→            LazyVGrid(columns: [
    44→                GridItem(.flexible()),
    45→                GridItem(.flexible()),
    46→                GridItem(.flexible()),
    47→                GridItem(.flexible())
    48→            ], spacing: 16) {
    49→                StatCard(
    50→                    title: "Total",
    51→                    value: dataManager.totalDomains,
    52→                    icon: "globe",
    53→                    color: .blue
    54→                )
    55→
    56→                StatCard(
    57→                    title: "Online",
    58→                    value: dataManager.onlineCount,
    59→                    subtitle: percentage(dataManager.onlineCount),
    60→                    icon: "checkmark.circle.fill",
    61→                    color: .green
    62→                )
    63→
    64→                StatCard(
    65→                    title: "Offline",
    66→                    value: dataManager.offlineCount,
    67→                    subtitle: percentage(dataManager.offlineCount),
    68→                    icon: "xmark.circle.fill",
    69→                    color: .red
    70→                )
    71→
    72→                StatCard(
    73→                    title: "Pending",
    74→                    value: dataManager.pendingCount,
    75→                    subtitle: percentage(dataManager.pendingCount),
    76→                    icon: "clock.fill",
    77→                    color: .orange
    78→                )
    79→            }
    80→
    81→            // Linha 2: Detalhes
    82→            LazyVGrid(columns: [
    83→                GridItem(.flexible()),
    84→                GridItem(.flexible()),
    85→                GridItem(.flexible()),
    86→                GridItem(.flexible())
    87→            ], spacing: 16) {
    88→                StatCard(
    89→                    title: "DNS Failed",
    90→                    value: dataManager.dnsFailureCount,
    91→                    subtitle: percentage(dataManager.dnsFailureCount),
    92→                    icon: "network.slash",
    93→                    color: .pink
    94→                )
    95→
    96→                StatCard(
    97→                    title: "Errors",
    98→                    value: dataManager.errorCount,
    99→                    subtitle: percentage(dataManager.errorCount),
   100→                    icon: "exclamationmark.triangle.fill",
   101→                    color: .purple
   102→                )
   103→
   104→                // .com.br específico
   105→                StatCard(
   106→                    title: ".com.br",
   107→                    value: dataManager.comBrCount,
   108→                    subtitle: "🇧🇷 Brasileiros",
   109→                    icon: "flag.fill",
   110→                    color: .green
   111→                )
   112→
   113→                StatCard(
   114→                    title: "Processed",
   115→                    value: dataManager.processedDomains,
   116→                    subtitle: percentage(dataManager.processedDomains),
   117→                    icon: "checkmark.seal.fill",
   118→                    color: .teal
   119→                )
   120→            }
   121→        }
   122→    }
   123→
   124→    // MARK: - Distribution
   125→
   126→    private var distributionSection: some View {
   127→        VStack(alignment: .leading, spacing: 12) {
   128→            Text("Status Distribution")
   129→                .font(.headline)
   130→
   131→            // Horizontal bar
   132→            GeometryReader { geometry in
   133→                HStack(spacing: 2) {
   134→                    let total = max(1, dataManager.totalDomains)
   135→                    let width = geometry.size.width
   136→
   137→                    Rectangle()
   138→                        .fill(Color.green)
   139→                        .frame(width: width * CGFloat(dataManager.onlineCount) / CGFloat(total))
   140→
   141→                    Rectangle()
   142→                        .fill(Color.red)
   143→                        .frame(width: width * CGFloat(dataManager.offlineCount) / CGFloat(total))
   144→
   145→                    Rectangle()
   146→                        .fill(Color.orange)
   147→                        .frame(width: width * CGFloat(dataManager.pendingCount) / CGFloat(total))
   148→
   149→                    Rectangle()
   150→                        .fill(Color.purple)
   151→                        .frame(width: width * CGFloat(dataManager.errorCount) / CGFloat(total))
   152→                }
   153→                .clipShape(Capsule())
   154→            }
   155→            .frame(height: 12)
   156→
   157→            // Legend
   158→            HStack(spacing: 16) {
   159→                LegendItem(color: .green, label: "Online", count: dataManager.onlineCount)
   160→                LegendItem(color: .red, label: "Offline", count: dataManager.offlineCount)
   161→                LegendItem(color: .pink, label: "DNS Fail", count: dataManager.dnsFailureCount)
   162→                LegendItem(color: .orange, label: "Pending", count: dataManager.pendingCount)
   163→                LegendItem(color: .purple, label: "Errors", count: dataManager.errorCount)
   164→            }
   165→            .font(.caption)
   166→        }
   167→        .padding()
   168→        .background(Color(nsColor: .windowBackgroundColor))
   169→        .clipShape(RoundedRectangle(cornerRadius: 12))
   170→    }
   171→
   172→    // MARK: - Session Info
   173→
   174→    private func sessionInfoSection(_ session: ValidationSessionEntity) -> some View {
   175→        VStack(alignment: .leading, spacing: 12) {
   176→            Text("Current Session")
   177→                .font(.headline)
   178→
   179→            HStack {
   180→                VStack(alignment: .leading, spacing: 4) {
   181→                    Text(session.name)
   182→                        .font(.title3.bold())
   183→
   184→                    Text("Source: \(session.sourceFileName)")
   185→                        .font(.caption)
   186→                        .foregroundStyle(.secondary)
   187→
   188→                    Text("Created: \(session.createdAt.formatted())")
   189→                        .font(.caption)
   190→                        .foregroundStyle(.secondary)
   191→                }
   192→
   193→                Spacer()
   194→
   195→                VStack(alignment: .trailing, spacing: 4) {
   196→                    Text("\(Int(session.progress * 100))%")
   197→                        .font(.title.bold().monospacedDigit())
   198→
   199→                    Text("Complete")
   200→                        .font(.caption)
   201→                        .foregroundStyle(.secondary)
   202→                }
   203→            }
   204→
   205→            ProgressView(value: session.progress)
   206→                .tint(.blue)
   207→        }
   208→        .padding()
   209→        .background(Color(nsColor: .windowBackgroundColor))
   210→        .clipShape(RoundedRectangle(cornerRadius: 12))
   211→    }
   212→
   213→    // MARK: - Helpers
   214→
   215→    private func percentage(_ value: Int) -> String {
   216→        guard dataManager.totalDomains > 0 else { return "0%" }
   217→        let percent = Double(value) / Double(dataManager.totalDomains) * 100
   218→        return String(format: "%.1f%%", percent)
   219→    }
   220→}
   221→
   222→// MARK: - Supporting Views
   223→
   224→struct LegendItem: View {
   225→    let color: Color
   226→    let label: String
   227→    let count: Int
   228→
   229→    var body: some View {
   230→        HStack(spacing: 4) {
   231→            Circle()
   232→                .fill(color)
   233→                .frame(width: 8, height: 8)
   234→            Text(label)
   235→            Text("(\(count.formatted()))")
   236→                .foregroundStyle(.secondary)
   237→        }
   238→    }
   239→}
   240→
   241→#Preview {
   242→    OverviewDashboardView()
   243→        .environmentObject(DataManager.shared)
   244→        .frame(width: 800, height: 600)
   245→}
   246→

<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

struct OverviewDashboardView: View {
    @EnvironmentObject var dataManager: DataManager

    var body: some View {
        ScrollView {
            VStack(spacing: 24) {
                // Stats Cards
                statsCardsSection

                // Progress Section (when validating)
                if let progress = dataManager.validationProgress {
                    ValidationProgressView(progress: progress)
                        .padding()
                        .background(Color(nsColor: .windowBackgroundColor))
                        .clipShape(RoundedRectangle(cornerRadius: 16))
                }

                // Distribution Chart
                if dataManager.totalDomains > 0 {
                    distributionSection
                }

                // Session Info
                if let session = dataManager.currentSession {
                    sessionInfoSection(session)
                }

                Spacer()
            }
            .padding()
        }
        .navigationTitle("Overview")
        .background(Color(nsColor: .controlBackgroundColor))
    }

    // MARK: - Stats Cards

    private var statsCardsSection: some View {
        VStack(spacing: 16) {
            // Linha 1: Principais
            LazyVGrid(columns: [
                GridItem(.flexible()),
                GridItem(.flexible()),
                GridItem(.flexible()),
                GridItem(.flexible())
            ], spacing: 16) {
                StatCard(
                    title: "Total",
                    value: dataManager.totalDomains,
                    icon: "globe",
                    color: .blue
                )

                StatCard(
                    title: "Online",
                    value: dataManager.onlineCount,
                    subtitle: percentage(dataManager.onlineCount),
                    icon: "checkmark.circle.fill",
                    color: .green
                )

                StatCard(
                    title: "Offline",
                    value: dataManager.offlineCount,
                    subtitle: percentage(dataManager.offlineCount),
                    icon: "xmark.circle.fill",
                    color: .red
                )

                StatCard(
                    title: "Pending",
                    value: dataManager.pendingCount,
                    subtitle: percentage(dataManager.pendingCount),
                    icon: "clock.fill",
                    color: .orange
                )
            }

            // Linha 2: Detalhes
            LazyVGrid(columns: [
                GridItem(.flexible()),
                GridItem(.flexible()),
                GridItem(.flexible()),
                GridItem(.flexible())
            ], spacing: 16) {
                StatCard(
                    title: "DNS Failed",
                    value: dataManager.dnsFailureCount,
                    subtitle: percentage(dataManager.dnsFailureCount),
                    icon: "network.slash",
                    color: .pink
                )

                StatCard(
                    title: "Errors",
                    value: dataManager.errorCount,
                    subtitle: percentage(dataManager.errorCount),
                    icon: "exclamationmark.triangle.fill",
                    color: .purple
                )

                // .com.br específico
                StatCard(
                    title: ".com.br",
                    value: dataManager.comBrCount,
                    subtitle: "🇧🇷 Brasileiros",
                    icon: "flag.fill",
                    color: .green
                )

                StatCard(
                    title: "Processed",
                    value: dataManager.processedDomains,
                    subtitle: percentage(dataManager.processedDomains),
                    icon: "checkmark.seal.fill",
                    color: .teal
                )
            }
        }
    }

    // MARK: - Distribution

    private var distributionSection: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Status Distribution")
                .font(.headline)

            // Horizontal bar
            GeometryReader { geometry in
                HStack(spacing: 2) {
                    let total = max(1, dataManager.totalDomains)
                    let width = geometry.size.width

                    Rectangle()
                        .fill(Color.green)
                        .frame(width: width * CGFloat(dataManager.onlineCount) / CGFloat(total))

                    Rectangle()
                        .fill(Color.red)
                        .frame(width: width * CGFloat(dataManager.offlineCount) / CGFloat(total))

                    Rectangle()
                        .fill(Color.orange)
                        .frame(width: width * CGFloat(dataManager.pendingCount) / CGFloat(total))

                    Rectangle()
                        .fill(Color.purple)
                        .frame(width: width * CGFloat(dataManager.errorCount) / CGFloat(total))
                }
                .clipShape(Capsule())
            }
            .frame(height: 12)

            // Legend
            HStack(spacing: 16) {
                LegendItem(color: .green, label: "Online", count: dataManager.onlineCount)
                LegendItem(color: .red, label: "Offline", count: dataManager.offlineCount)
                LegendItem(color: .pink, label: "DNS Fail", count: dataManager.dnsFailureCount)
                LegendItem(color: .orange, label: "Pending", count: dataManager.pendingCount)
                LegendItem(color: .purple, label: "Errors", count: dataManager.errorCount)
            }
            .font(.caption)
        }
        .padding()
        .background(Color(nsColor: .windowBackgroundColor))
        .clipShape(RoundedRectangle(cornerRadius: 12))
    }

    // MARK: - Session Info

    private func sessionInfoSection(_ session: ValidationSessionEntity) -> some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Current Session")
                .font(.headline)

            HStack {
                VStack(alignment: .leading, spacing: 4) {
                    Text(session.name)
                        .font(.title3.bold())

                    Text("Source: \(session.sourceFileName)")
                        .font(.caption)
                        .foregroundStyle(.secondary)

                    Text("Created: \(session.createdAt.formatted())")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }

                Spacer()

                VStack(alignment: .trailing, spacing: 4) {
                    Text("\(Int(session.progress * 100))%")
                        .font(.title.bold().monospacedDigit())

                    Text("Complete")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }

            ProgressView(value: session.progress)
                .tint(.blue)
        }
        .padding()
        .background(Color(nsColor: .windowBackgroundColor))
        .clipShape(RoundedRectangle(cornerRadius: 12))
    }

    // MARK: - Helpers

    private func percentage(_ value: Int) -> String {
        guard dataManager.totalDomains > 0 else { return "0%" }
        let percent = Double(value) / Double(dataManager.totalDomains) * 100
        return String(format: "%.1f%%", percent)
    }
}

// MARK: - Supporting Views

struct LegendItem: View {
    let color: Color
    let label: String
    let count: Int

    var body: some View {
        HStack(spacing: 4) {
            Circle()
                .fill(color)
                .frame(width: 8, height: 8)
            Text(label)
            Text("(\(count.formatted()))")
                .foregroundStyle(.secondary)
        }
    }
}

#Preview {
    OverviewDashboardView()
        .environmentObject(DataManager.shared)
        .frame(width: 800, height: 600)
}


     1→import SwiftUI
     2→
     3→struct StatCard: View {
     4→    let title: String
     5→    let value: Int
     6→    var subtitle: String? = nil
     7→    let icon: String
     8→    let color: Color
     9→
    10→    var body: some View {
    11→        VStack(alignment: .leading, spacing: 8) {
    12→            HStack {
    13→                Image(systemName: icon)
    14→                    .font(.title2)
    15→                    .foregroundStyle(color)
    16→
    17→                Spacer()
    18→
    19→                if let subtitle = subtitle {
    20→                    Text(subtitle)
    21→                        .font(.caption)
    22→                        .foregroundStyle(.secondary)
    23→                        .padding(.horizontal, 8)
    24→                        .padding(.vertical, 4)
    25→                        .background(color.opacity(0.1))
    26→                        .clipShape(Capsule())
    27→                }
    28→            }
    29→
    30→            VStack(alignment: .leading, spacing: 2) {
    31→                Text(formatValue(value))
    32→                    .font(.system(size: 28, weight: .bold, design: .rounded))
    33→                    .contentTransition(.numericText())
    34→
    35→                Text(title)
    36→                    .font(.subheadline)
    37→                    .foregroundStyle(.secondary)
    38→            }
    39→        }
    40→        .padding()
    41→        .frame(maxWidth: .infinity, alignment: .leading)
    42→        .background(Color(nsColor: .windowBackgroundColor))
    43→        .clipShape(RoundedRectangle(cornerRadius: 12))
    44→    }
    45→
    46→    private func formatValue(_ value: Int) -> String {
    47→        if value >= 1_000_000 {
    48→            return String(format: "%.2fM", Double(value) / 1_000_000)
    49→        } else if value >= 1000 {
    50→            return String(format: "%.1fK", Double(value) / 1000)
    51→        }
    52→        return value.formatted()
    53→    }
    54→}
    55→
    56→struct MetricCard: View {
    57→    let label: String
    58→    let value: String
    59→    var icon: String? = nil
    60→    var color: Color = .primary
    61→    var trend: TrendDirection? = nil
    62→
    63→    enum TrendDirection {
    64→        case up, down, stable
    65→    }
    66→
    67→    var body: some View {
    68→        VStack(alignment: .leading, spacing: 4) {
    69→            HStack(spacing: 4) {
    70→                if let icon = icon {
    71→                    Image(systemName: icon)
    72→                        .font(.caption)
    73→                        .foregroundStyle(.secondary)
    74→                }
    75→                Text(label)
    76→                    .font(.caption)
    77→                    .foregroundStyle(.secondary)
    78→            }
    79→
    80→            HStack(spacing: 4) {
    81→                Text(value)
    82→                    .font(.title3.bold().monospacedDigit())
    83→                    .foregroundStyle(color)
    84→                    .contentTransition(.numericText())
    85→
    86→                if let trend = trend {
    87→                    trendIndicator(trend)
    88→                }
    89→            }
    90→        }
    91→    }
    92→
    93→    @ViewBuilder
    94→    private func trendIndicator(_ trend: TrendDirection) -> some View {
    95→        switch trend {
    96→        case .up:
    97→            Image(systemName: "arrow.up.right")
    98→                .font(.caption)
    99→                .foregroundStyle(.green)
   100→        case .down:
   101→            Image(systemName: "arrow.down.right")
   102→                .font(.caption)
   103→                .foregroundStyle(.red)
   104→        case .stable:
   105→            Image(systemName: "arrow.right")
   106→                .font(.caption)
   107→                .foregroundStyle(.gray)
   108→        }
   109→    }
   110→}
   111→
   112→#Preview {
   113→    HStack {
   114→        StatCard(title: "Online", value: 245230, subtitle: "81.7%", icon: "checkmark.circle.fill", color: .green)
   115→        StatCard(title: "Offline", value: 54770, subtitle: "18.3%", icon: "xmark.circle.fill", color: .red)
   116→    }
   117→    .padding()
   118→}
   119→

<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

struct StatCard: View {
    let title: String
    let value: Int
    var subtitle: String? = nil
    let icon: String
    let color: Color

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack {
                Image(systemName: icon)
                    .font(.title2)
                    .foregroundStyle(color)

                Spacer()

                if let subtitle = subtitle {
                    Text(subtitle)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                        .padding(.horizontal, 8)
                        .padding(.vertical, 4)
                        .background(color.opacity(0.1))
                        .clipShape(Capsule())
                }
            }

            VStack(alignment: .leading, spacing: 2) {
                Text(formatValue(value))
                    .font(.system(size: 28, weight: .bold, design: .rounded))
                    .contentTransition(.numericText())

                Text(title)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }
        }
        .padding()
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(Color(nsColor: .windowBackgroundColor))
        .clipShape(RoundedRectangle(cornerRadius: 12))
    }

    private func formatValue(_ value: Int) -> String {
        if value >= 1_000_000 {
            return String(format: "%.2fM", Double(value) / 1_000_000)
        } else if value >= 1000 {
            return String(format: "%.1fK", Double(value) / 1000)
        }
        return value.formatted()
    }
}

struct MetricCard: View {
    let label: String
    let value: String
    var icon: String? = nil
    var color: Color = .primary
    var trend: TrendDirection? = nil

    enum TrendDirection {
        case up, down, stable
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            HStack(spacing: 4) {
                if let icon = icon {
                    Image(systemName: icon)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
                Text(label)
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            HStack(spacing: 4) {
                Text(value)
                    .font(.title3.bold().monospacedDigit())
                    .foregroundStyle(color)
                    .contentTransition(.numericText())

                if let trend = trend {
                    trendIndicator(trend)
                }
            }
        }
    }

    @ViewBuilder
    private func trendIndicator(_ trend: TrendDirection) -> some View {
        switch trend {
        case .up:
            Image(systemName: "arrow.up.right")
                .font(.caption)
                .foregroundStyle(.green)
        case .down:
            Image(systemName: "arrow.down.right")
                .font(.caption)
                .foregroundStyle(.red)
        case .stable:
            Image(systemName: "arrow.right")
                .font(.caption)
                .foregroundStyle(.gray)
        }
    }
}

#Preview {
    HStack {
        StatCard(title: "Online", value: 245230, subtitle: "81.7%", icon: "checkmark.circle.fill", color: .green)
        StatCard(title: "Offline", value: 54770, subtitle: "18.3%", icon: "xmark.circle.fill", color: .red)
    }
    .padding()
}


TodoWrite

Explore existing DomainChecker patterns and architecture

Exploring existing DomainChecker patterns

Design StreamingFileReader for 170GB file processing

Design data models (ExtractedData, ExtractionStats, etc.)

Design RegexExtractor service with Swift Regex patterns

Design CPF/CNPJ validation logic

Design CheckpointManager for pause/resume

Design UI views structure

Document complete implementation plan


Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable

Explore existing DomainChecker patterns and architecture

Exploring existing DomainChecker patterns

Design StreamingFileReader for 170GB file processing

Design data models (ExtractedData, ExtractionStats, etc.)

Design RegexExtractor service with Swift Regex patterns

Design CPF/CNPJ validation logic

Design CheckpointManager for pause/resume

Design UI views structure

Document complete implementation plan


Let me search for any existing file streaming patterns in the workspace:


No files found


Error: File content (33658 tokens) exceeds maximum allowed tokens (25000). Please use offset and limit parameters to read specific portions of the file, or use the GrepTool to search for specific content.