     1→import SwiftUI
     2→
     3→enum NavigationItem: String, CaseIterable, Identifiable {
     4→    case dashboard = "Dashboard"
     5→    case currency = "Câmbio"
     6→    case rates = "Taxas"
     7→    case institutions = "Instituições"
     8→    case pix = "PIX"
     9→    case expectations = "Focus"
    10→
    11→    var id: String { rawValue }
    12→
    13→    var icon: String {
    14→        switch self {
    15→        case .dashboard: return "square.grid.2x2"
    16→        case .currency: return "dollarsign.circle"
    17→        case .rates: return "percent"
    18→        case .institutions: return "building.columns"
    19→        case .pix: return "qrcode"
    20→        case .expectations: return "chart.line.uptrend.xyaxis"
    21→        }
    22→    }
    23→
    24→    var color: Color {
    25→        switch self {
    26→        case .dashboard: return .bcbBlue
    27→        case .currency: return .bcbGreen
    28→        case .rates: return .bcbPurple
    29→        case .institutions: return .bcbPink
    30→        case .pix: return .green
    31→        case .expectations: return .bcbYellow
    32→        }
    33→    }
    34→}
    35→
    36→struct ContentView: View {
    37→    @EnvironmentObject var viewModel: DashboardViewModel
    38→    @State private var selectedItem: NavigationItem? = .dashboard
    39→    @State private var columnVisibility: NavigationSplitViewVisibility = .all
    40→    @State private var showingExportSheet = false
    41→    @State private var exportFormat: ExportFormat = .json
    42→
    43→    var body: some View {
    44→        NavigationSplitView(columnVisibility: $columnVisibility) {
    45→            SidebarView(selectedItem: $selectedItem)
    46→        } detail: {
    47→            Group {
    48→                switch selectedItem {
    49→                case .dashboard:
    50→                    DashboardView()
    51→                case .currency:
    52→                    CurrencyListView()
    53→                case .rates:
    54→                    RatesView()
    55→                case .institutions:
    56→                    InstitutionsView()
    57→                case .pix:
    58→                    PIXStatsView()
    59→                case .expectations:
    60→                    ExpectationsView()
    61→                case .none:
    62→                    WelcomeView()
    63→                }
    64→            }
    65→            .frame(maxWidth: .infinity, maxHeight: .infinity)
    66→        }
    67→        .navigationSplitViewStyle(.balanced)
    68→        .toolbar {
    69→            ToolbarItemGroup(placement: .navigation) {
    70→                // Status indicator
    71→                HStack(spacing: 6) {
    72→                    Circle()
    73→                        .fill(viewModel.errorMessage == nil ? .green : .red)
    74→                        .frame(width: 8, height: 8)
    75→
    76→                    if viewModel.isLoading {
    77→                        Text("Atualizando...")
    78→                            .font(.caption)
    79→                            .foregroundStyle(.secondary)
    80→                    } else if let error = viewModel.errorMessage {
    81→                        Text("Erro")
    82→                            .font(.caption)
    83→                            .foregroundStyle(.red)
    84→                            .help(error)
    85→                    } else {
    86→                        Text("Online")
    87→                            .font(.caption)
    88→                            .foregroundStyle(.secondary)
    89→                    }
    90→                }
    91→            }
    92→
    93→            ToolbarItemGroup(placement: .primaryAction) {
    94→                // Loading indicator
    95→                if viewModel.isLoading {
    96→                    ProgressView()
    97→                        .controlSize(.small)
    98→                }
    99→
   100→                // Quick values
   101→                QuickValuePill(
   102→                    label: "USD",
   103→                    value: viewModel.dollarQuote?.sellRate.toBRL() ?? "--",
   104→                    color: .bcbGreen
   105→                )
   106→
   107→                QuickValuePill(
   108→                    label: "SELIC",
   109→                    value: String(format: "%.2f%%", viewModel.selicTarget?.numericValue ?? 0.0),
   110→                    color: .bcbPurple
   111→                )
   112→
   113→                Divider()
   114→
   115→                // Refresh button
   116→                Button {
   117→                    Task {
   118→                        await viewModel.refreshAll()
   119→                    }
   120→                } label: {
   121→                    Image(systemName: "arrow.clockwise")
   122→                }
   123→                .keyboardShortcut("r", modifiers: .command)
   124→                .disabled(viewModel.isLoading)
   125→                .help("Atualizar (⌘R)")
   126→
   127→                // Export button
   128→                Menu {
   129→                    Button {
   130→                        exportFormat = .json
   131→                        exportData()
   132→                    } label: {
   133→                        Label("Exportar JSON", systemImage: "doc.text")
   134→                    }
   135→
   136→                    Button {
   137→                        exportFormat = .csv
   138→                        exportData()
   139→                    } label: {
   140→                        Label("Exportar CSV", systemImage: "tablecells")
   141→                    }
   142→
   143→                    Divider()
   144→
   145→                    Button {
   146→                        copyToClipboard()
   147→                    } label: {
   148→                        Label("Copiar Resumo", systemImage: "doc.on.doc")
   149→                    }
   150→                } label: {
   151→                    Image(systemName: "square.and.arrow.up")
   152→                }
   153→                .help("Exportar dados")
   154→
   155→                // Last update
   156→                if let lastUpdate = viewModel.lastUpdate {
   157→                    Text(lastUpdate.toRelativeString())
   158→                        .font(.caption)
   159→                        .foregroundStyle(.secondary)
   160→                        .help(lastUpdate.toFullBRString())
   161→                }
   162→            }
   163→        }
   164→        .task {
   165→            await viewModel.refreshAll()
   166→        }
   167→        .alert("Erro", isPresented: .constant(viewModel.errorMessage != nil)) {
   168→            Button("OK") {
   169→                viewModel.dismissError()
   170→            }
   171→            Button("Tentar Novamente") {
   172→                Task {
   173→                    await viewModel.refreshAll()
   174→                }
   175→            }
   176→        } message: {
   177→            Text(viewModel.errorMessage ?? "Erro desconhecido")
   178→        }
   179→    }
   180→
   181→    private func exportData() {
   182→        let panel = NSSavePanel()
   183→        panel.allowedContentTypes = exportFormat == .json ? [.json] : [.commaSeparatedText]
   184→        panel.nameFieldStringValue = "bcb-data-\(Date().toFilenameDateString()).\(exportFormat.rawValue)"
   185→
   186→        panel.begin { response in
   187→            if response == .OK, let url = panel.url {
   188→                let data = generateExportData(format: exportFormat)
   189→                try? data.write(to: url, atomically: true, encoding: .utf8)
   190→            }
   191→        }
   192→    }
   193→
   194→    private func generateExportData(format: ExportFormat) -> String {
   195→        switch format {
   196→        case .json:
   197→            return generateJSONExport()
   198→        case .csv:
   199→            return generateCSVExport()
   200→        }
   201→    }
   202→
   203→    private func generateJSONExport() -> String {
   204→        var export: [String: Any] = [:]
   205→
   206→        export["exportDate"] = Date().toFullBRString()
   207→        export["source"] = "Banco Central do Brasil"
   208→
   209→        if let dollar = viewModel.dollarQuote {
   210→            export["dollarQuote"] = [
   211→                "buy": dollar.buyRate,
   212→                "sell": dollar.sellRate,
   213→                "date": dollar.formattedDate
   214→            ]
   215→        }
   216→
   217→        if let euro = viewModel.euroQuote {
   218→            export["euroQuote"] = [
   219→                "buy": euro.buyRate,
   220→                "sell": euro.sellRate,
   221→                "date": euro.formattedDate
   222→            ]
   223→        }
   224→
   225→        var rates: [String: Double] = [:]
   226→        rates["selicTarget"] = viewModel.selicTarget?.numericValue ?? 0
   227→        rates["selicDaily"] = viewModel.selicDaily?.numericValue ?? 0
   228→        rates["cdi"] = viewModel.cdi?.numericValue ?? 0
   229→        rates["ipcaMonthly"] = viewModel.ipcaMonthly?.numericValue ?? 0
   230→        rates["ipca12m"] = viewModel.ipca12m?.numericValue ?? 0
   231→        export["rates"] = rates
   232→
   233→        if let selicExp = viewModel.focusStats.latestSelic {
   234→            export["focusExpectations"] = [
   235→                "selicExpected": selicExp.median,
   236→                "selicMeeting": selicExp.meeting
   237→            ]
   238→        }
   239→
   240→        if let jsonData = try? JSONSerialization.data(withJSONObject: export, options: .prettyPrinted),
   241→           let jsonString = String(data: jsonData, encoding: .utf8) {
   242→            return jsonString
   243→        }
   244→        return "{}"
   245→    }
   246→
   247→    private func generateCSVExport() -> String {
   248→        var csv = "Indicador,Valor,Data\n"
   249→
   250→        if let dollar = viewModel.dollarQuote {
   251→            csv += "Dólar (Compra),\(dollar.buyRate),\(dollar.formattedDate)\n"
   252→            csv += "Dólar (Venda),\(dollar.sellRate),\(dollar.formattedDate)\n"
   253→        }
   254→
   255→        if let euro = viewModel.euroQuote {
   256→            csv += "Euro (Compra),\(euro.buyRate),\(euro.formattedDate)\n"
   257→            csv += "Euro (Venda),\(euro.sellRate),\(euro.formattedDate)\n"
   258→        }
   259→
   260→        if let selic = viewModel.selicTarget {
   261→            csv += "SELIC Meta,\(selic.numericValue),\(selic.date)\n"
   262→        }
   263→
   264→        if let cdi = viewModel.cdi {
   265→            csv += "CDI,\(cdi.numericValue),\(cdi.date)\n"
   266→        }
   267→
   268→        if let ipca = viewModel.ipca12m {
   269→            csv += "IPCA 12m,\(ipca.numericValue),\(ipca.date)\n"
   270→        }
   271→
   272→        return csv
   273→    }
   274→
   275→    private func copyToClipboard() {
   276→        var summary = "📊 BCB Dashboard - \(Date().toFullBRString())\n\n"
   277→
   278→        if let dollar = viewModel.dollarQuote {
   279→            summary += "💵 Dólar: \(dollar.sellRate.toBRL())\n"
   280→        }
   281→
   282→        if let euro = viewModel.euroQuote {
   283→            summary += "💶 Euro: \(euro.sellRate.toBRL())\n"
   284→        }
   285→
   286→        if let selic = viewModel.selicTarget {
   287→            summary += "📈 SELIC: \(String(format: "%.2f%%", selic.numericValue))\n"
   288→        }
   289→
   290→        if let ipca = viewModel.ipca12m {
   291→            summary += "📉 IPCA 12m: \(String(format: "%.2f%%", ipca.numericValue))\n"
   292→        }
   293→
   294→        summary += "\nFonte: Banco Central do Brasil"
   295→
   296→        NSPasteboard.general.clearContents()
   297→        NSPasteboard.general.setString(summary, forType: .string)
   298→    }
   299→}
   300→
   301→enum ExportFormat: String {
   302→    case json
   303→    case csv
   304→}
   305→
   306→// MARK: - Quick Value Pill
   307→
   308→struct QuickValuePill: View {
   309→    let label: String
   310→    let value: String
   311→    let color: Color
   312→
   313→    var body: some View {
   314→        HStack(spacing: 4) {
   315→            Text(label)
   316→                .font(.caption2)
   317→                .foregroundStyle(.secondary)
   318→
   319→            Text(value)
   320→                .font(.caption)
   321→                .fontWeight(.semibold)
   322→                .foregroundStyle(color)
   323→        }
   324→        .padding(.horizontal, 8)
   325→        .padding(.vertical, 4)
   326→        .background(color.opacity(0.1))
   327→        .clipShape(Capsule())
   328→    }
   329→}
   330→
   331→// MARK: - Welcome View
   332→
   333→struct WelcomeView: View {
   334→    var body: some View {
   335→        VStack(spacing: 20) {
   336→            Image(systemName: "building.columns.fill")
   337→                .font(.system(size: 64))
   338→                .foregroundStyle(Color.bcbBlue)
   339→
   340→            Text("BCB Dashboard")
   341→                .font(.largeTitle)
   342→                .fontWeight(.bold)
   343→
   344→            Text("Selecione um item no menu lateral")
   345→                .foregroundStyle(.secondary)
   346→        }
   347→    }
   348→}
   349→
   350→// MARK: - Sidebar View
   351→
   352→struct SidebarView: View {
   353→    @Binding var selectedItem: NavigationItem?
   354→    @EnvironmentObject var viewModel: DashboardViewModel
   355→
   356→    var body: some View {
   357→        List(selection: $selectedItem) {
   358→            Section("Overview") {
   359→                NavigationLink(value: NavigationItem.dashboard) {
   360→                    SidebarRow(
   361→                        icon: "square.grid.2x2",
   362→                        title: "Dashboard",
   363→                        color: .bcbBlue,
   364→                        badge: nil
   365→                    )
   366→                }
   367→            }
   368→
   369→            Section("Mercado") {
   370→                NavigationLink(value: NavigationItem.currency) {
   371→                    SidebarRow(
   372→                        icon: "dollarsign.circle",
   373→                        title: "Câmbio",
   374→                        color: .bcbGreen,
   375→                        badge: viewModel.dollarQuote?.sellRate.toBRL()
   376→                    )
   377→                }
   378→
   379→                NavigationLink(value: NavigationItem.rates) {
   380→                    SidebarRow(
   381→                        icon: "percent",
   382→                        title: "Taxas",
   383→                        color: .bcbPurple,
   384→                        badge: viewModel.selicTarget.map { String(format: "%.1f%%", $0.numericValue) }
   385→                    )
   386→                }
   387→            }
   388→
   389→            Section("Análise") {
   390→                NavigationLink(value: NavigationItem.expectations) {
   391→                    SidebarRow(
   392→                        icon: "chart.line.uptrend.xyaxis",
   393→                        title: "Focus",
   394→                        color: .bcbYellow,
   395→                        badge: viewModel.focusStats.latestSelic.map { String(format: "%.1f%%", $0.median) }
   396→                    )
   397→                }
   398→
   399→                NavigationLink(value: NavigationItem.pix) {
   400→                    SidebarRow(
   401→                        icon: "qrcode",
   402→                        title: "PIX",
   403→                        color: .green,
   404→                        badge: viewModel.pixStats.latestDaily.map { "\($0.quantity / 1_000_000)M" }
   405→                    )
   406→                }
   407→            }
   408→
   409→            Section("Referência") {
   410→                NavigationLink(value: NavigationItem.institutions) {
   411→                    SidebarRow(
   412→                        icon: "building.columns",
   413→                        title: "Instituições",
   414→                        color: .bcbPink,
   415→                        badge: viewModel.banks.isEmpty ? nil : "\(viewModel.banks.count + viewModel.cooperatives.count)"
   416→                    )
   417→                }
   418→            }
   419→
   420→            Section {
   421→                // Status Footer
   422→                VStack(alignment: .leading, spacing: 8) {
   423→                    if let lastUpdate = viewModel.lastUpdate {
   424→                        HStack {
   425→                            Image(systemName: "clock")
   426→                                .font(.caption2)
   427→                            Text(lastUpdate.toRelativeString())
   428→                                .font(.caption2)
   429→                        }
   430→                        .foregroundStyle(.secondary)
   431→                    }
   432→
   433→                    if viewModel.isLoading {
   434→                        HStack {
   435→                            ProgressView()
   436→                                .controlSize(.mini)
   437→                            Text("Atualizando...")
   438→                                .font(.caption2)
   439→                        }
   440→                        .foregroundStyle(.secondary)
   441→                    }
   442→                }
   443→                .padding(.vertical, 4)
   444→            }
   445→        }
   446→        .listStyle(.sidebar)
   447→        .navigationTitle("BCB")
   448→        .frame(minWidth: 220)
   449→    }
   450→}
   451→
   452→struct SidebarRow: View {
   453→    let icon: String
   454→    let title: String
   455→    let color: Color
   456→    let badge: String?
   457→
   458→    var body: some View {
   459→        HStack {
   460→            Image(systemName: icon)
   461→                .foregroundStyle(color)
   462→                .frame(width: 24)
   463→
   464→            Text(title)
   465→
   466→            Spacer()
   467→
   468→            if let badge = badge {
   469→                Text(badge)
   470→                    .font(.caption2)
   471→                    .fontWeight(.medium)
   472→                    .foregroundStyle(color)
   473→                    .padding(.horizontal, 6)
   474→                    .padding(.vertical, 2)
   475→                    .background(color.opacity(0.15))
   476→                    .clipShape(Capsule())
   477→            }
   478→        }
   479→    }
   480→}
   481→
   482→// MARK: - Date Extension
   483→
   484→extension Date {
   485→    func toRelativeString() -> String {
   486→        let formatter = RelativeDateTimeFormatter()
   487→        formatter.unitsStyle = .abbreviated
   488→        formatter.locale = Locale(identifier: "pt_BR")
   489→        return formatter.localizedString(for: self, relativeTo: Date())
   490→    }
   491→
   492→    func toFilenameDateString() -> String {
   493→        let formatter = DateFormatter()
   494→        formatter.dateFormat = "yyyy-MM-dd-HHmmss"
   495→        return formatter.string(from: self)
   496→    }
   497→}
   498→
   499→#Preview {
   500→    ContentView()
   501→        .environmentObject(DashboardViewModel())
   502→}
   503→

<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

enum NavigationItem: String, CaseIterable, Identifiable {
    case dashboard = "Dashboard"
    case currency = "Câmbio"
    case rates = "Taxas"
    case institutions = "Instituições"
    case pix = "PIX"
    case expectations = "Focus"

    var id: String { rawValue }

    var icon: String {
        switch self {
        case .dashboard: return "square.grid.2x2"
        case .currency: return "dollarsign.circle"
        case .rates: return "percent"
        case .institutions: return "building.columns"
        case .pix: return "qrcode"
        case .expectations: return "chart.line.uptrend.xyaxis"
        }
    }

    var color: Color {
        switch self {
        case .dashboard: return .bcbBlue
        case .currency: return .bcbGreen
        case .rates: return .bcbPurple
        case .institutions: return .bcbPink
        case .pix: return .green
        case .expectations: return .bcbYellow
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var viewModel: DashboardViewModel
    @State private var selectedItem: NavigationItem? = .dashboard
    @State private var columnVisibility: NavigationSplitViewVisibility = .all
    @State private var showingExportSheet = false
    @State private var exportFormat: ExportFormat = .json

    var body: some View {
        NavigationSplitView(columnVisibility: $columnVisibility) {
            SidebarView(selectedItem: $selectedItem)
        } detail: {
            Group {
                switch selectedItem {
                case .dashboard:
                    DashboardView()
                case .currency:
                    CurrencyListView()
                case .rates:
                    RatesView()
                case .institutions:
                    InstitutionsView()
                case .pix:
                    PIXStatsView()
                case .expectations:
                    ExpectationsView()
                case .none:
                    WelcomeView()
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
        .navigationSplitViewStyle(.balanced)
        .toolbar {
            ToolbarItemGroup(placement: .navigation) {
                // Status indicator
                HStack(spacing: 6) {
                    Circle()
                        .fill(viewModel.errorMessage == nil ? .green : .red)
                        .frame(width: 8, height: 8)

                    if viewModel.isLoading {
                        Text("Atualizando...")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                    } else if let error = viewModel.errorMessage {
                        Text("Erro")
                            .font(.caption)
                            .foregroundStyle(.red)
                            .help(error)
                    } else {
                        Text("Online")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                    }
                }
            }

            ToolbarItemGroup(placement: .primaryAction) {
                // Loading indicator
                if viewModel.isLoading {
                    ProgressView()
                        .controlSize(.small)
                }

                // Quick values
                QuickValuePill(
                    label: "USD",
                    value: viewModel.dollarQuote?.sellRate.toBRL() ?? "--",
                    color: .bcbGreen
                )

                QuickValuePill(
                    label: "SELIC",
                    value: String(format: "%.2f%%", viewModel.selicTarget?.numericValue ?? 0.0),
                    color: .bcbPurple
                )

                Divider()

                // Refresh button
                Button {
                    Task {
                        await viewModel.refreshAll()
                    }
                } label: {
                    Image(systemName: "arrow.clockwise")
                }
                .keyboardShortcut("r", modifiers: .command)
                .disabled(viewModel.isLoading)
                .help("Atualizar (⌘R)")

                // Export button
                Menu {
                    Button {
                        exportFormat = .json
                        exportData()
                    } label: {
                        Label("Exportar JSON", systemImage: "doc.text")
                    }

                    Button {
                        exportFormat = .csv
                        exportData()
                    } label: {
                        Label("Exportar CSV", systemImage: "tablecells")
                    }

                    Divider()

                    Button {
                        copyToClipboard()
                    } label: {
                        Label("Copiar Resumo", systemImage: "doc.on.doc")
                    }
                } label: {
                    Image(systemName: "square.and.arrow.up")
                }
                .help("Exportar dados")

                // Last update
                if let lastUpdate = viewModel.lastUpdate {
                    Text(lastUpdate.toRelativeString())
                        .font(.caption)
                        .foregroundStyle(.secondary)
                        .help(lastUpdate.toFullBRString())
                }
            }
        }
        .task {
            await viewModel.refreshAll()
        }
        .alert("Erro", isPresented: .constant(viewModel.errorMessage != nil)) {
            Button("OK") {
                viewModel.dismissError()
            }
            Button("Tentar Novamente") {
                Task {
                    await viewModel.refreshAll()
                }
            }
        } message: {
            Text(viewModel.errorMessage ?? "Erro desconhecido")
        }
    }

    private func exportData() {
        let panel = NSSavePanel()
        panel.allowedContentTypes = exportFormat == .json ? [.json] : [.commaSeparatedText]
        panel.nameFieldStringValue = "bcb-data-\(Date().toFilenameDateString()).\(exportFormat.rawValue)"

        panel.begin { response in
            if response == .OK, let url = panel.url {
                let data = generateExportData(format: exportFormat)
                try? data.write(to: url, atomically: true, encoding: .utf8)
            }
        }
    }

    private func generateExportData(format: ExportFormat) -> String {
        switch format {
        case .json:
            return generateJSONExport()
        case .csv:
            return generateCSVExport()
        }
    }

    private func generateJSONExport() -> String {
        var export: [String: Any] = [:]

        export["exportDate"] = Date().toFullBRString()
        export["source"] = "Banco Central do Brasil"

        if let dollar = viewModel.dollarQuote {
            export["dollarQuote"] = [
                "buy": dollar.buyRate,
                "sell": dollar.sellRate,
                "date": dollar.formattedDate
            ]
        }

        if let euro = viewModel.euroQuote {
            export["euroQuote"] = [
                "buy": euro.buyRate,
                "sell": euro.sellRate,
                "date": euro.formattedDate
            ]
        }

        var rates: [String: Double] = [:]
        rates["selicTarget"] = viewModel.selicTarget?.numericValue ?? 0
        rates["selicDaily"] = viewModel.selicDaily?.numericValue ?? 0
        rates["cdi"] = viewModel.cdi?.numericValue ?? 0
        rates["ipcaMonthly"] = viewModel.ipcaMonthly?.numericValue ?? 0
        rates["ipca12m"] = viewModel.ipca12m?.numericValue ?? 0
        export["rates"] = rates

        if let selicExp = viewModel.focusStats.latestSelic {
            export["focusExpectations"] = [
                "selicExpected": selicExp.median,
                "selicMeeting": selicExp.meeting
            ]
        }

        if let jsonData = try? JSONSerialization.data(withJSONObject: export, options: .prettyPrinted),
           let jsonString = String(data: jsonData, encoding: .utf8) {
            return jsonString
        }
        return "{}"
    }

    private func generateCSVExport() -> String {
        var csv = "Indicador,Valor,Data\n"

        if let dollar = viewModel.dollarQuote {
            csv += "Dólar (Compra),\(dollar.buyRate),\(dollar.formattedDate)\n"
            csv += "Dólar (Venda),\(dollar.sellRate),\(dollar.formattedDate)\n"
        }

        if let euro = viewModel.euroQuote {
            csv += "Euro (Compra),\(euro.buyRate),\(euro.formattedDate)\n"
            csv += "Euro (Venda),\(euro.sellRate),\(euro.formattedDate)\n"
        }

        if let selic = viewModel.selicTarget {
            csv += "SELIC Meta,\(selic.numericValue),\(selic.date)\n"
        }

        if let cdi = viewModel.cdi {
            csv += "CDI,\(cdi.numericValue),\(cdi.date)\n"
        }

        if let ipca = viewModel.ipca12m {
            csv += "IPCA 12m,\(ipca.numericValue),\(ipca.date)\n"
        }

        return csv
    }

    private func copyToClipboard() {
        var summary = "📊 BCB Dashboard - \(Date().toFullBRString())\n\n"

        if let dollar = viewModel.dollarQuote {
            summary += "💵 Dólar: \(dollar.sellRate.toBRL())\n"
        }

        if let euro = viewModel.euroQuote {
            summary += "💶 Euro: \(euro.sellRate.toBRL())\n"
        }

        if let selic = viewModel.selicTarget {
            summary += "📈 SELIC: \(String(format: "%.2f%%", selic.numericValue))\n"
        }

        if let ipca = viewModel.ipca12m {
            summary += "📉 IPCA 12m: \(String(format: "%.2f%%", ipca.numericValue))\n"
        }

        summary += "\nFonte: Banco Central do Brasil"

        NSPasteboard.general.clearContents()
        NSPasteboard.general.setString(summary, forType: .string)
    }
}

enum ExportFormat: String {
    case json
    case csv
}

// MARK: - Quick Value Pill

struct QuickValuePill: View {
    let label: String
    let value: String
    let color: Color

    var body: some View {
        HStack(spacing: 4) {
            Text(label)
                .font(.caption2)
                .foregroundStyle(.secondary)

            Text(value)
                .font(.caption)
                .fontWeight(.semibold)
                .foregroundStyle(color)
        }
        .padding(.horizontal, 8)
        .padding(.vertical, 4)
        .background(color.opacity(0.1))
        .clipShape(Capsule())
    }
}

// MARK: - Welcome View

struct WelcomeView: View {
    var body: some View {
        VStack(spacing: 20) {
            Image(systemName: "building.columns.fill")
                .font(.system(size: 64))
                .foregroundStyle(Color.bcbBlue)

            Text("BCB Dashboard")
                .font(.largeTitle)
                .fontWeight(.bold)

            Text("Selecione um item no menu lateral")
                .foregroundStyle(.secondary)
        }
    }
}

// MARK: - Sidebar View

struct SidebarView: View {
    @Binding var selectedItem: NavigationItem?
    @EnvironmentObject var viewModel: DashboardViewModel

    var body: some View {
        List(selection: $selectedItem) {
            Section("Overview") {
                NavigationLink(value: NavigationItem.dashboard) {
                    SidebarRow(
                        icon: "square.grid.2x2",
                        title: "Dashboard",
                        color: .bcbBlue,
                        badge: nil
                    )
                }
            }

            Section("Mercado") {
                NavigationLink(value: NavigationItem.currency) {
                    SidebarRow(
                        icon: "dollarsign.circle",
                        title: "Câmbio",
                        color: .bcbGreen,
                        badge: viewModel.dollarQuote?.sellRate.toBRL()
                    )
                }

                NavigationLink(value: NavigationItem.rates) {
                    SidebarRow(
                        icon: "percent",
                        title: "Taxas",
                        color: .bcbPurple,
                        badge: viewModel.selicTarget.map { String(format: "%.1f%%", $0.numericValue) }
                    )
                }
            }

            Section("Análise") {
                NavigationLink(value: NavigationItem.expectations) {
                    SidebarRow(
                        icon: "chart.line.uptrend.xyaxis",
                        title: "Focus",
                        color: .bcbYellow,
                        badge: viewModel.focusStats.latestSelic.map { String(format: "%.1f%%", $0.median) }
                    )
                }

                NavigationLink(value: NavigationItem.pix) {
                    SidebarRow(
                        icon: "qrcode",
                        title: "PIX",
                        color: .green,
                        badge: viewModel.pixStats.latestDaily.map { "\($0.quantity / 1_000_000)M" }
                    )
                }
            }

            Section("Referência") {
                NavigationLink(value: NavigationItem.institutions) {
                    SidebarRow(
                        icon: "building.columns",
                        title: "Instituições",
                        color: .bcbPink,
                        badge: viewModel.banks.isEmpty ? nil : "\(viewModel.banks.count + viewModel.cooperatives.count)"
                    )
                }
            }

            Section {
                // Status Footer
                VStack(alignment: .leading, spacing: 8) {
                    if let lastUpdate = viewModel.lastUpdate {
                        HStack {
                            Image(systemName: "clock")
                                .font(.caption2)
                            Text(lastUpdate.toRelativeString())
                                .font(.caption2)
                        }
                        .foregroundStyle(.secondary)
                    }

                    if viewModel.isLoading {
                        HStack {
                            ProgressView()
                                .controlSize(.mini)
                            Text("Atualizando...")
                                .font(.caption2)
                        }
                        .foregroundStyle(.secondary)
                    }
                }
                .padding(.vertical, 4)
            }
        }
        .listStyle(.sidebar)
        .navigationTitle("BCB")
        .frame(minWidth: 220)
    }
}

struct SidebarRow: View {
    let icon: String
    let title: String
    let color: Color
    let badge: String?

    var body: some View {
        HStack {
            Image(systemName: icon)
                .foregroundStyle(color)
                .frame(width: 24)

            Text(title)

            Spacer()

            if let badge = badge {
                Text(badge)
                    .font(.caption2)
                    .fontWeight(.medium)
                    .foregroundStyle(color)
                    .padding(.horizontal, 6)
                    .padding(.vertical, 2)
                    .background(color.opacity(0.15))
                    .clipShape(Capsule())
            }
        }
    }
}

// MARK: - Date Extension

extension Date {
    func toRelativeString() -> String {
        let formatter = RelativeDateTimeFormatter()
        formatter.unitsStyle = .abbreviated
        formatter.locale = Locale(identifier: "pt_BR")
        return formatter.localizedString(for: self, relativeTo: Date())
    }

    func toFilenameDateString() -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd-HHmmss"
        return formatter.string(from: self)
    }
}

#Preview {
    ContentView()
        .environmentObject(DashboardViewModel())
}


     1→import SwiftUI
     2→import Charts
     3→
     4→struct DashboardView: View {
     5→    @EnvironmentObject var viewModel: DashboardViewModel
     6→
     7→    var body: some View {
     8→        ScrollView {
     9→            VStack(spacing: 20) {
    10→                // Header
    11→                HStack {
    12→                    Text("Overview")
    13→                        .font(.title2)
    14→                        .fontWeight(.semibold)
    15→
    16→                    Spacer()
    17→
    18→                    if let lastUpdate = viewModel.lastUpdate {
    19→                        Label(lastUpdate.toFullBRString(), systemImage: "clock")
    20→                            .font(.caption)
    21→                            .foregroundStyle(.secondary)
    22→                    }
    23→                }
    24→                .padding(.horizontal)
    25→
    26→                // Main Cards
    27→                LazyVGrid(columns: [
    28→                    GridItem(.flexible(), spacing: 16),
    29→                    GridItem(.flexible(), spacing: 16),
    30→                    GridItem(.flexible(), spacing: 16),
    31→                    GridItem(.flexible(), spacing: 16)
    32→                ], spacing: 16) {
    33→                    // USD Card
    34→                    CurrencyCard(
    35→                        title: "Dólar (USD)",
    36→                        symbol: "🇺🇸",
    37→                        value: viewModel.dollarQuote?.sellRate ?? 0,
    38→                        change: viewModel.dollarChange,
    39→                        subtitle: viewModel.dollarQuote?.formattedTime ?? "--"
    40→                    )
    41→
    42→                    // EUR Card
    43→                    CurrencyCard(
    44→                        title: "Euro (EUR)",
    45→                        symbol: "🇪🇺",
    46→                        value: viewModel.euroQuote?.sellRate ?? 0,
    47→                        change: 0,
    48→                        subtitle: viewModel.euroQuote?.formattedTime ?? "--"
    49→                    )
    50→
    51→                    // SELIC Card
    52→                    RateCard(
    53→                        title: "SELIC Meta",
    54→                        icon: "percent",
    55→                        iconColor: .bcbPurple,
    56→                        value: viewModel.selicTarget?.numericValue ?? 0,
    57→                        unit: "% a.a.",
    58→                        subtitle: viewModel.selicTarget?.date ?? "--"
    59→                    )
    60→
    61→                    // IPCA Card
    62→                    RateCard(
    63→                        title: "IPCA 12m",
    64→                        icon: "chart.line.uptrend.xyaxis",
    65→                        iconColor: .bcbYellow,
    66→                        value: viewModel.ipca12m?.numericValue ?? 0,
    67→                        unit: "%",
    68→                        subtitle: viewModel.ipca12m?.date ?? "--"
    69→                    )
    70→                }
    71→                .padding(.horizontal)
    72→
    73→                // Secondary Row
    74→                LazyVGrid(columns: [
    75→                    GridItem(.flexible(), spacing: 16),
    76→                    GridItem(.flexible(), spacing: 16),
    77→                    GridItem(.flexible(), spacing: 16)
    78→                ], spacing: 16) {
    79→                    // CDI Card
    80→                    RateCard(
    81→                        title: "CDI",
    82→                        icon: "banknote",
    83→                        iconColor: .bcbPink,
    84→                        value: viewModel.cdi?.numericValue ?? 0,
    85→                        unit: "% a.a.",
    86→                        subtitle: viewModel.cdi?.date ?? "--"
    87→                    )
    88→
    89→                    // IPCA Mensal
    90→                    RateCard(
    91→                        title: "IPCA Mensal",
    92→                        icon: "calendar",
    93→                        iconColor: .bcbYellow,
    94→                        value: viewModel.ipcaMonthly?.numericValue ?? 0,
    95→                        unit: "%",
    96→                        subtitle: viewModel.ipcaMonthly?.date ?? "--"
    97→                    )
    98→
    99→                    // Juro Real
   100→                    RateCard(
   101→                        title: "Juro Real",
   102→                        icon: "arrow.up.arrow.down",
   103→                        iconColor: .bcbGreen,
   104→                        value: viewModel.realInterestRate,
   105→                        unit: "% a.a.",
   106→                        subtitle: "SELIC - IPCA"
   107→                    )
   108→                }
   109→                .padding(.horizontal)
   110→
   111→                // Focus Market Expectations Section
   112→                VStack(alignment: .leading, spacing: 12) {
   113→                    HStack {
   114→                        Image(systemName: "chart.line.uptrend.xyaxis")
   115→                            .foregroundStyle(Color.bcbBlue)
   116→                        Text("Expectativas de Mercado (Focus)")
   117→                            .font(.headline)
   118→
   119→                        Spacer()
   120→
   121→                        if viewModel.focusLoading {
   122→                            ProgressView()
   123→                                .controlSize(.small)
   124→                        }
   125→                    }
   126→
   127→                    LazyVGrid(columns: [
   128→                        GridItem(.flexible(), spacing: 16),
   129→                        GridItem(.flexible(), spacing: 16),
   130→                        GridItem(.flexible(), spacing: 16),
   131→                        GridItem(.flexible(), spacing: 16),
   132→                        GridItem(.flexible(), spacing: 16)
   133→                    ], spacing: 16) {
   134→                        // SELIC Expected
   135→                        FocusExpectationCard(
   136→                            title: "SELIC Esperada",
   137→                            value: viewModel.focusStats.latestSelic.map { String(format: "%.2f%%", $0.median) } ?? "--",
   138→                            subtitle: viewModel.focusStats.latestSelic?.formattedMeeting ?? "Próxima reunião",
   139→                            icon: "percent",
   140→                            color: .bcbPurple
   141→                        )
   142→
   143→                        // IPCA Expected
   144→                        FocusExpectationCard(
   145→                            title: "IPCA 12m",
   146→                            value: viewModel.focusStats.latestIPCA12m.map { String(format: "%.2f%%", $0.median) } ?? "--",
   147→                            subtitle: "Expectativa",
   148→                            icon: "chart.bar.fill",
   149→                            color: .bcbYellow
   150→                        )
   151→
   152→                        // IGP-M Expected
   153→                        FocusExpectationCard(
   154→                            title: "IGP-M 12m",
   155→                            value: viewModel.focusStats.latestIGPM12m.map { String(format: "%.2f%%", $0.median) } ?? "--",
   156→                            subtitle: "Expectativa",
   157→                            icon: "building.2.fill",
   158→                            color: .bcbPink
   159→                        )
   160→
   161→                        // PIB Expected
   162→                        FocusExpectationCard(
   163→                            title: "PIB \(Calendar.current.component(.year, from: Date()))",
   164→                            value: viewModel.focusStats.latestPIBYear.map { String(format: "%.2f%%", $0.median) } ?? "--",
   165→                            subtitle: "Crescimento",
   166→                            icon: "arrow.up.right",
   167→                            color: .bcbGreen
   168→                        )
   169→
   170→                        // Câmbio Expected
   171→                        FocusExpectationCard(
   172→                            title: "USD/BRL",
   173→                            value: {
   174→                                let currentYear = Calendar.current.component(.year, from: Date())
   175→                                if let cambio = viewModel.focusStats.annualCambio.first(where: { $0.referenceYear == "\(currentYear)" && $0.baseCalculo == 0 }) {
   176→                                    return String(format: "R$ %.2f", cambio.median)
   177→                                }
   178→                                return "--"
   179→                            }(),
   180→                            subtitle: "Fim do ano",
   181→                            icon: "dollarsign.circle.fill",
   182→                            color: .bcbBlue
   183→                        )
   184→                    }
   185→                }
   186→                .padding()
   187→                .background(Color(NSColor.controlBackgroundColor))
   188→                .clipShape(RoundedRectangle(cornerRadius: 12))
   189→                .padding(.horizontal)
   190→
   191→                // Charts Section
   192→                HStack(spacing: 16) {
   193→                    // Dollar Chart
   194→                    VStack(alignment: .leading, spacing: 12) {
   195→                        Text("Dólar - Últimos 30 dias")
   196→                            .font(.headline)
   197→
   198→                        if !viewModel.dollarHistory.isEmpty {
   199→                            DollarChartView(data: viewModel.dollarHistory)
   200→                                .frame(height: 200)
   201→                        } else {
   202→                            ProgressView()
   203→                                .frame(height: 200)
   204→                        }
   205→                    }
   206→                    .cardStyle()
   207→
   208→                    // IPCA Chart
   209→                    VStack(alignment: .leading, spacing: 12) {
   210→                        Text("IPCA - Últimos 12 meses")
   211→                            .font(.headline)
   212→
   213→                        if !viewModel.ipcaHistory.isEmpty {
   214→                            IPCAChartView(data: viewModel.ipcaHistory)
   215→                                .frame(height: 200)
   216→                        } else {
   217→                            ProgressView()
   218→                                .frame(height: 200)
   219→                        }
   220→                    }
   221→                    .cardStyle()
   222→                }
   223→                .padding(.horizontal)
   224→
   225→                // History Table
   226→                VStack(alignment: .leading, spacing: 12) {
   227→                    Text("Histórico do Dólar")
   228→                        .font(.headline)
   229→
   230→                    DollarHistoryTable(data: Array(viewModel.dollarHistory.suffix(10).reversed()))
   231→                }
   232→                .cardStyle()
   233→                .padding(.horizontal)
   234→
   235→                Spacer(minLength: 20)
   236→            }
   237→            .padding(.vertical)
   238→        }
   239→        .background(Color(NSColor.windowBackgroundColor))
   240→        .task {
   241→            // Load Focus data if not already loaded
   242→            if viewModel.focusStats.selicExpectations.isEmpty {
   243→                await viewModel.loadFocusStats()
   244→            }
   245→        }
   246→    }
   247→}
   248→
   249→// MARK: - Focus Expectation Card
   250→
   251→struct FocusExpectationCard: View {
   252→    let title: String
   253→    let value: String
   254→    let subtitle: String
   255→    let icon: String
   256→    let color: Color
   257→
   258→    var body: some View {
   259→        VStack(alignment: .leading, spacing: 8) {
   260→            HStack {
   261→                Image(systemName: icon)
   262→                    .font(.system(size: 14))
   263→                    .foregroundStyle(color)
   264→
   265→                Text(title)
   266→                    .font(.caption)
   267→                    .foregroundStyle(.secondary)
   268→                    .lineLimit(1)
   269→            }
   270→
   271→            Text(value)
   272→                .font(.system(size: 18, weight: .bold, design: .rounded))
   273→                .foregroundStyle(color)
   274→
   275→            Text(subtitle)
   276→                .font(.caption2)
   277→                .foregroundStyle(.tertiary)
   278→                .lineLimit(1)
   279→        }
   280→        .frame(maxWidth: .infinity, alignment: .leading)
   281→        .padding(12)
   282→        .background(color.opacity(0.1))
   283→        .clipShape(RoundedRectangle(cornerRadius: 10))
   284→    }
   285→}
   286→
   287→// MARK: - Currency Card
   288→
   289→struct CurrencyCard: View {
   290→    let title: String
   291→    let symbol: String
   292→    let value: Double
   293→    let change: Double
   294→    let subtitle: String
   295→
   296→    var body: some View {
   297→        VStack(alignment: .leading, spacing: 12) {
   298→            HStack {
   299→                Text(symbol)
   300→                    .font(.title2)
   301→
   302→                VStack(alignment: .leading, spacing: 2) {
   303→                    Text(title)
   304→                        .font(.caption)
   305→                        .foregroundStyle(.secondary)
   306→                }
   307→
   308→                Spacer()
   309→            }
   310→
   311→            Text(value.toBRL())
   312→                .font(.system(size: 24, weight: .bold, design: .rounded))
   313→                .foregroundStyle(.primary)
   314→
   315→            HStack {
   316→                if change != 0 {
   317→                    Label(
   318→                        String(format: "%@%.2f%%", change >= 0 ? "+" : "", change),
   319→                        systemImage: change >= 0 ? "arrow.up.right" : "arrow.down.right"
   320→                    )
   321→                    .font(.caption)
   322→                    .foregroundStyle(change >= 0 ? Color.bcbGreen : Color.bcbRed)
   323→                }
   324→
   325→                Spacer()
   326→
   327→                Text(subtitle)
   328→                    .font(.caption2)
   329→                    .foregroundStyle(.tertiary)
   330→            }
   331→        }
   332→        .cardStyle()
   333→    }
   334→}
   335→
   336→// MARK: - Rate Card
   337→
   338→struct RateCard: View {
   339→    let title: String
   340→    let icon: String
   341→    let iconColor: Color
   342→    let value: Double
   343→    let unit: String
   344→    let subtitle: String
   345→
   346→    var body: some View {
   347→        VStack(alignment: .leading, spacing: 12) {
   348→            HStack {
   349→                Image(systemName: icon)
   350→                    .font(.title2)
   351→                    .foregroundStyle(iconColor)
   352→
   353→                Text(title)
   354→                    .font(.caption)
   355→                    .foregroundStyle(.secondary)
   356→
   357→                Spacer()
   358→            }
   359→
   360→            HStack(alignment: .firstTextBaseline, spacing: 4) {
   361→                Text(String(format: "%.2f", value))
   362→                    .font(.system(size: 24, weight: .bold, design: .rounded))
   363→
   364→                Text(unit)
   365→                    .font(.caption)
   366→                    .foregroundStyle(.secondary)
   367→            }
   368→
   369→            Text(subtitle)
   370→                .font(.caption2)
   371→                .foregroundStyle(.tertiary)
   372→        }
   373→        .cardStyle()
   374→    }
   375→}
   376→
   377→// MARK: - Charts
   378→
   379→struct DollarChartView: View {
   380→    let data: [DollarQuote]
   381→
   382→    var body: some View {
   383→        Chart(data) { quote in
   384→            if let date = quote.dateTime {
   385→                LineMark(
   386→                    x: .value("Data", date),
   387→                    y: .value("Cotação", quote.sellRate)
   388→                )
   389→                .foregroundStyle(Color.bcbGreen)
   390→
   391→                AreaMark(
   392→                    x: .value("Data", date),
   393→                    y: .value("Cotação", quote.sellRate)
   394→                )
   395→                .foregroundStyle(
   396→                    LinearGradient(
   397→                        colors: [Color.bcbGreen.opacity(0.3), Color.bcbGreen.opacity(0.0)],
   398→                        startPoint: .top,
   399→                        endPoint: .bottom
   400→                    )
   401→                )
   402→            }
   403→        }
   404→        .chartYScale(domain: .automatic(includesZero: false))
   405→        .chartXAxis {
   406→            AxisMarks(values: .automatic(desiredCount: 6)) { value in
   407→                AxisGridLine()
   408→                AxisValueLabel(format: .dateTime.day().month())
   409→            }
   410→        }
   411→    }
   412→}
   413→
   414→struct IPCAChartView: View {
   415→    let data: [TimeSeriesValue]
   416→
   417→    var body: some View {
   418→        Chart(data) { item in
   419→            BarMark(
   420→                x: .value("Mês", item.date),
   421→                y: .value("IPCA", item.numericValue)
   422→            )
   423→            .foregroundStyle(item.numericValue >= 0 ? Color.bcbYellow : Color.bcbRed)
   424→        }
   425→        .chartXAxis {
   426→            AxisMarks(values: .automatic(desiredCount: 6)) { _ in
   427→                AxisGridLine()
   428→                AxisValueLabel()
   429→            }
   430→        }
   431→    }
   432→}
   433→
   434→// MARK: - History Table
   435→
   436→struct DollarHistoryTable: View {
   437→    let data: [DollarQuote]
   438→
   439→    var body: some View {
   440→        VStack(spacing: 0) {
   441→            // Header
   442→            HStack {
   443→                Text("Data")
   444→                    .frame(maxWidth: .infinity, alignment: .leading)
   445→                Text("Compra")
   446→                    .frame(maxWidth: .infinity, alignment: .trailing)
   447→                Text("Venda")
   448→                    .frame(maxWidth: .infinity, alignment: .trailing)
   449→                Text("Horário")
   450→                    .frame(maxWidth: .infinity, alignment: .trailing)
   451→            }
   452→            .font(.caption)
   453→            .foregroundStyle(.secondary)
   454→            .padding(.vertical, 8)
   455→
   456→            Divider()
   457→
   458→            // Rows
   459→            ForEach(data) { quote in
   460→                HStack {
   461→                    Text(quote.formattedDate)
   462→                        .frame(maxWidth: .infinity, alignment: .leading)
   463→                    Text(quote.buyRate.toBRL())
   464→                        .frame(maxWidth: .infinity, alignment: .trailing)
   465→                    Text(quote.sellRate.toBRL())
   466→                        .frame(maxWidth: .infinity, alignment: .trailing)
   467→                    Text(quote.formattedTime)
   468→                        .frame(maxWidth: .infinity, alignment: .trailing)
   469→                }
   470→                .font(.system(.body, design: .monospaced))
   471→                .padding(.vertical, 6)
   472→
   473→                if quote.id != data.last?.id {
   474→                    Divider()
   475→                }
   476→            }
   477→        }
   478→    }
   479→}
   480→
   481→#Preview {
   482→    DashboardView()
   483→        .environmentObject(DashboardViewModel())
   484→        .frame(width: 1200, height: 800)
   485→}
   486→

<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
import Charts

struct DashboardView: View {
    @EnvironmentObject var viewModel: DashboardViewModel

    var body: some View {
        ScrollView {
            VStack(spacing: 20) {
                // Header
                HStack {
                    Text("Overview")
                        .font(.title2)
                        .fontWeight(.semibold)

                    Spacer()

                    if let lastUpdate = viewModel.lastUpdate {
                        Label(lastUpdate.toFullBRString(), systemImage: "clock")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                    }
                }
                .padding(.horizontal)

                // Main Cards
                LazyVGrid(columns: [
                    GridItem(.flexible(), spacing: 16),
                    GridItem(.flexible(), spacing: 16),
                    GridItem(.flexible(), spacing: 16),
                    GridItem(.flexible(), spacing: 16)
                ], spacing: 16) {
                    // USD Card
                    CurrencyCard(
                        title: "Dólar (USD)",
                        symbol: "🇺🇸",
                        value: viewModel.dollarQuote?.sellRate ?? 0,
                        change: viewModel.dollarChange,
                        subtitle: viewModel.dollarQuote?.formattedTime ?? "--"
                    )

                    // EUR Card
                    CurrencyCard(
                        title: "Euro (EUR)",
                        symbol: "🇪🇺",
                        value: viewModel.euroQuote?.sellRate ?? 0,
                        change: 0,
                        subtitle: viewModel.euroQuote?.formattedTime ?? "--"
                    )

                    // SELIC Card
                    RateCard(
                        title: "SELIC Meta",
                        icon: "percent",
                        iconColor: .bcbPurple,
                        value: viewModel.selicTarget?.numericValue ?? 0,
                        unit: "% a.a.",
                        subtitle: viewModel.selicTarget?.date ?? "--"
                    )

                    // IPCA Card
                    RateCard(
                        title: "IPCA 12m",
                        icon: "chart.line.uptrend.xyaxis",
                        iconColor: .bcbYellow,
                        value: viewModel.ipca12m?.numericValue ?? 0,
                        unit: "%",
                        subtitle: viewModel.ipca12m?.date ?? "--"
                    )
                }
                .padding(.horizontal)

                // Secondary Row
                LazyVGrid(columns: [
                    GridItem(.flexible(), spacing: 16),
                    GridItem(.flexible(), spacing: 16),
                    GridItem(.flexible(), spacing: 16)
                ], spacing: 16) {
                    // CDI Card
                    RateCard(
                        title: "CDI",
                        icon: "banknote",
                        iconColor: .bcbPink,
                        value: viewModel.cdi?.numericValue ?? 0,
                        unit: "% a.a.",
                        subtitle: viewModel.cdi?.date ?? "--"
                    )

                    // IPCA Mensal
                    RateCard(
                        title: "IPCA Mensal",
                        icon: "calendar",
                        iconColor: .bcbYellow,
                        value: viewModel.ipcaMonthly?.numericValue ?? 0,
                        unit: "%",
                        subtitle: viewModel.ipcaMonthly?.date ?? "--"
                    )

                    // Juro Real
                    RateCard(
                        title: "Juro Real",
                        icon: "arrow.up.arrow.down",
                        iconColor: .bcbGreen,
                        value: viewModel.realInterestRate,
                        unit: "% a.a.",
                        subtitle: "SELIC - IPCA"
                    )
                }
                .padding(.horizontal)

                // Focus Market Expectations Section
                VStack(alignment: .leading, spacing: 12) {
                    HStack {
                        Image(systemName: "chart.line.uptrend.xyaxis")
                            .foregroundStyle(Color.bcbBlue)
                        Text("Expectativas de Mercado (Focus)")
                            .font(.headline)

                        Spacer()

                        if viewModel.focusLoading {
                            ProgressView()
                                .controlSize(.small)
                        }
                    }

                    LazyVGrid(columns: [
                        GridItem(.flexible(), spacing: 16),
                        GridItem(.flexible(), spacing: 16),
                        GridItem(.flexible(), spacing: 16),
                        GridItem(.flexible(), spacing: 16),
                        GridItem(.flexible(), spacing: 16)
                    ], spacing: 16) {
                        // SELIC Expected
                        FocusExpectationCard(
                            title: "SELIC Esperada",
                            value: viewModel.focusStats.latestSelic.map { String(format: "%.2f%%", $0.median) } ?? "--",
                            subtitle: viewModel.focusStats.latestSelic?.formattedMeeting ?? "Próxima reunião",
                            icon: "percent",
                            color: .bcbPurple
                        )

                        // IPCA Expected
                        FocusExpectationCard(
                            title: "IPCA 12m",
                            value: viewModel.focusStats.latestIPCA12m.map { String(format: "%.2f%%", $0.median) } ?? "--",
                            subtitle: "Expectativa",
                            icon: "chart.bar.fill",
                            color: .bcbYellow
                        )

                        // IGP-M Expected
                        FocusExpectationCard(
                            title: "IGP-M 12m",
                            value: viewModel.focusStats.latestIGPM12m.map { String(format: "%.2f%%", $0.median) } ?? "--",
                            subtitle: "Expectativa",
                            icon: "building.2.fill",
                            color: .bcbPink
                        )

                        // PIB Expected
                        FocusExpectationCard(
                            title: "PIB \(Calendar.current.component(.year, from: Date()))",
                            value: viewModel.focusStats.latestPIBYear.map { String(format: "%.2f%%", $0.median) } ?? "--",
                            subtitle: "Crescimento",
                            icon: "arrow.up.right",
                            color: .bcbGreen
                        )

                        // Câmbio Expected
                        FocusExpectationCard(
                            title: "USD/BRL",
                            value: {
                                let currentYear = Calendar.current.component(.year, from: Date())
                                if let cambio = viewModel.focusStats.annualCambio.first(where: { $0.referenceYear == "\(currentYear)" && $0.baseCalculo == 0 }) {
                                    return String(format: "R$ %.2f", cambio.median)
                                }
                                return "--"
                            }(),
                            subtitle: "Fim do ano",
                            icon: "dollarsign.circle.fill",
                            color: .bcbBlue
                        )
                    }
                }
                .padding()
                .background(Color(NSColor.controlBackgroundColor))
                .clipShape(RoundedRectangle(cornerRadius: 12))
                .padding(.horizontal)

                // Charts Section
                HStack(spacing: 16) {
                    // Dollar Chart
                    VStack(alignment: .leading, spacing: 12) {
                        Text("Dólar - Últimos 30 dias")
                            .font(.headline)

                        if !viewModel.dollarHistory.isEmpty {
                            DollarChartView(data: viewModel.dollarHistory)
                                .frame(height: 200)
                        } else {
                            ProgressView()
                                .frame(height: 200)
                        }
                    }
                    .cardStyle()

                    // IPCA Chart
                    VStack(alignment: .leading, spacing: 12) {
                        Text("IPCA - Últimos 12 meses")
                            .font(.headline)

                        if !viewModel.ipcaHistory.isEmpty {
                            IPCAChartView(data: viewModel.ipcaHistory)
                                .frame(height: 200)
                        } else {
                            ProgressView()
                                .frame(height: 200)
                        }
                    }
                    .cardStyle()
                }
                .padding(.horizontal)

                // History Table
                VStack(alignment: .leading, spacing: 12) {
                    Text("Histórico do Dólar")
                        .font(.headline)

                    DollarHistoryTable(data: Array(viewModel.dollarHistory.suffix(10).reversed()))
                }
                .cardStyle()
                .padding(.horizontal)

                Spacer(minLength: 20)
            }
            .padding(.vertical)
        }
        .background(Color(NSColor.windowBackgroundColor))
        .task {
            // Load Focus data if not already loaded
            if viewModel.focusStats.selicExpectations.isEmpty {
                await viewModel.loadFocusStats()
            }
        }
    }
}

// MARK: - Focus Expectation Card

struct FocusExpectationCard: View {
    let title: String
    let value: String
    let subtitle: String
    let icon: String
    let color: Color

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

                Text(title)
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .lineLimit(1)
            }

            Text(value)
                .font(.system(size: 18, weight: .bold, design: .rounded))
                .foregroundStyle(color)

            Text(subtitle)
                .font(.caption2)
                .foregroundStyle(.tertiary)
                .lineLimit(1)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(12)
        .background(color.opacity(0.1))
        .clipShape(RoundedRectangle(cornerRadius: 10))
    }
}

// MARK: - Currency Card

struct CurrencyCard: View {
    let title: String
    let symbol: String
    let value: Double
    let change: Double
    let subtitle: String

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack {
                Text(symbol)
                    .font(.title2)

                VStack(alignment: .leading, spacing: 2) {
                    Text(title)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }

                Spacer()
            }

            Text(value.toBRL())
                .font(.system(size: 24, weight: .bold, design: .rounded))
                .foregroundStyle(.primary)

            HStack {
                if change != 0 {
                    Label(
                        String(format: "%@%.2f%%", change >= 0 ? "+" : "", change),
                        systemImage: change >= 0 ? "arrow.up.right" : "arrow.down.right"
                    )
                    .font(.caption)
                    .foregroundStyle(change >= 0 ? Color.bcbGreen : Color.bcbRed)
                }

                Spacer()

                Text(subtitle)
                    .font(.caption2)
                    .foregroundStyle(.tertiary)
            }
        }
        .cardStyle()
    }
}

// MARK: - Rate Card

struct RateCard: View {
    let title: String
    let icon: String
    let iconColor: Color
    let value: Double
    let unit: String
    let subtitle: String

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

                Text(title)
                    .font(.caption)
                    .foregroundStyle(.secondary)

                Spacer()
            }

            HStack(alignment: .firstTextBaseline, spacing: 4) {
                Text(String(format: "%.2f", value))
                    .font(.system(size: 24, weight: .bold, design: .rounded))

                Text(unit)
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            Text(subtitle)
                .font(.caption2)
                .foregroundStyle(.tertiary)
        }
        .cardStyle()
    }
}

// MARK: - Charts

struct DollarChartView: View {
    let data: [DollarQuote]

    var body: some View {
        Chart(data) { quote in
            if let date = quote.dateTime {
                LineMark(
                    x: .value("Data", date),
                    y: .value("Cotação", quote.sellRate)
                )
                .foregroundStyle(Color.bcbGreen)

                AreaMark(
                    x: .value("Data", date),
                    y: .value("Cotação", quote.sellRate)
                )
                .foregroundStyle(
                    LinearGradient(
                        colors: [Color.bcbGreen.opacity(0.3), Color.bcbGreen.opacity(0.0)],
                        startPoint: .top,
                        endPoint: .bottom
                    )
                )
            }
        }
        .chartYScale(domain: .automatic(includesZero: false))
        .chartXAxis {
            AxisMarks(values: .automatic(desiredCount: 6)) { value in
                AxisGridLine()
                AxisValueLabel(format: .dateTime.day().month())
            }
        }
    }
}

struct IPCAChartView: View {
    let data: [TimeSeriesValue]

    var body: some View {
        Chart(data) { item in
            BarMark(
                x: .value("Mês", item.date),
                y: .value("IPCA", item.numericValue)
            )
            .foregroundStyle(item.numericValue >= 0 ? Color.bcbYellow : Color.bcbRed)
        }
        .chartXAxis {
            AxisMarks(values: .automatic(desiredCount: 6)) { _ in
                AxisGridLine()
                AxisValueLabel()
            }
        }
    }
}

// MARK: - History Table

struct DollarHistoryTable: View {
    let data: [DollarQuote]

    var body: some View {
        VStack(spacing: 0) {
            // Header
            HStack {
                Text("Data")
                    .frame(maxWidth: .infinity, alignment: .leading)
                Text("Compra")
                    .frame(maxWidth: .infinity, alignment: .trailing)
                Text("Venda")
                    .frame(maxWidth: .infinity, alignment: .trailing)
                Text("Horário")
                    .frame(maxWidth: .infinity, alignment: .trailing)
            }
            .font(.caption)
            .foregroundStyle(.secondary)
            .padding(.vertical, 8)

            Divider()

            // Rows
            ForEach(data) { quote in
                HStack {
                    Text(quote.formattedDate)
                        .frame(maxWidth: .infinity, alignment: .leading)
                    Text(quote.buyRate.toBRL())
                        .frame(maxWidth: .infinity, alignment: .trailing)
                    Text(quote.sellRate.toBRL())
                        .frame(maxWidth: .infinity, alignment: .trailing)
                    Text(quote.formattedTime)
                        .frame(maxWidth: .infinity, alignment: .trailing)
                }
                .font(.system(.body, design: .monospaced))
                .padding(.vertical, 6)

                if quote.id != data.last?.id {
                    Divider()
                }
            }
        }
    }
}

#Preview {
    DashboardView()
        .environmentObject(DashboardViewModel())
        .frame(width: 1200, height: 800)
}