import Foundation import SwiftUI struct ProductDetailSheet: View { let product: StoreCatalogProduct let imageURL: String? let storeId: String let currentQuantityForItemId: (String) -> Int let onAdd: (CartItemState) -> Void @Environment(\.dismiss) var dismiss @State var selectedAddonItemIds: Set = [] @State var quantity: Int = 0 private var selectedAddonItems: [StoreAddonItem] { product.addonGroups .flatMap(\.items) .filter { selectedAddonItemIds.contains($0.id) } } private var addonsTotal: Double { selectedAddonItems.reduce(0) { $0 + ($1.price ?? 0) } } private var unitPrice: Double { (product.price ?? 0) + addonsTotal } private var totalPrice: Double { unitPrice * Double(quantity) } private var cartItemId: String { let addonKey = selectedAddonItemIds.sorted().joined(separator: ",") return "\(storeId)::\(product.id)::\(addonKey)" } private var selectedAddonsSummary: String? { let names = selectedAddonItems.map(\.name) if names.isEmpty { return nil } return names.joined(separator: ", ") } private var addButtonTitle: String { if quantity <= 0 { return "Remover do carrinho" } return "Atualizar • \(formatCurrency(totalPrice))" } var body: some View { ScrollView(showsIndicators: false) { VStack(alignment: .leading, spacing: 16) { AsyncStoreImage(imageURL: imageURL) .frame(height: 220) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusXL, style: .continuous)) Text(product.name) .font(AppTypography.heading2) .foregroundStyle(AppColors.textPrimary) if let description = product.description, description.isEmpty == false { Text(description) .font(AppTypography.body) .foregroundStyle(AppColors.textMuted) } Text(formatCurrency(unitPrice)) .font(AppTypography.heading2) .foregroundStyle(AppColors.primary) if addonsTotal > 0 { Text("Inclui adicionais: \(formatCurrency(addonsTotal))") .font(.caption) .foregroundStyle(AppColors.textMuted) } if product.addonGroups.isEmpty == false { Text("Adicionais") .font(AppTypography.heading3) .foregroundStyle(AppColors.textPrimary) ForEach(product.addonGroups) { group in VStack(alignment: .leading, spacing: 8) { Text(group.name) .font(AppTypography.heading3) .foregroundStyle(AppColors.textPrimary) ForEach(group.items) { item in Button { if selectedAddonItemIds.contains(item.id) { selectedAddonItemIds.remove(item.id) } else { selectedAddonItemIds.insert(item.id) } } label: { HStack { Image(systemName: selectedAddonItemIds.contains(item.id) ? "checkmark.circle.fill" : "circle") .font(.system(size: 18, weight: .semibold)) .foregroundStyle(selectedAddonItemIds.contains(item.id) ? AppColors.primary : AppColors.textMuted) Text(item.name) .font(AppTypography.body) .foregroundStyle(AppColors.textMuted) Spacer() Text(String(format: "+ R$ %.2f", item.price ?? 0).replacingOccurrences(of: ".", with: ",")) .font(AppTypography.body) .foregroundStyle(AppColors.textPrimary) } } .buttonStyle(.plain) } } .padding(12) .background(AppColors.surface) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) } } } .padding(20) .padding(.bottom, 80) } .safeAreaInset(edge: .bottom) { HStack(spacing: 12) { HStack(spacing: 10) { Button(action: { if quantity > 0 { quantity -= 1 } }) { Image(systemName: "minus") .font(.system(size: 14, weight: .bold)) .foregroundStyle(AppColors.textPrimary) .frame(width: 32, height: 32) .background(AppColors.surface) .clipShape(Circle()) } .buttonStyle(.plain) .disabled(quantity <= 0) Text("\(quantity)") .font(AppTypography.heading3) .foregroundStyle(AppColors.textPrimary) .frame(minWidth: 20) Button(action: { quantity += 1 }) { Image(systemName: "plus") .font(.system(size: 14, weight: .bold)) .foregroundStyle(AppColors.textPrimary) .frame(width: 32, height: 32) .background(AppColors.surface) .clipShape(Circle()) } .buttonStyle(.plain) } .padding(.horizontal, 8) .frame(height: 48) .background(AppColors.surface) .clipShape(RoundedRectangle(cornerRadius: 14, style: .continuous)) .buttonStyle(.plain) PrimaryButton(title: addButtonTitle) { let item = CartItemState( id: cartItemId, productId: product.id, storeId: storeId, name: product.name, details: selectedAddonsSummary, quantity: quantity, unitPrice: unitPrice ) onAdd(item) dismiss() } } .padding(.horizontal, 20) .padding(.top, 8) .padding(.bottom, 12) .background(.ultraThinMaterial) } .background(AppColors.backgroundLight.ignoresSafeArea()) .navigationTitle("Detalhes") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Fechar") { dismiss() } .foregroundStyle(AppColors.primary) } } .onAppear { quantity = currentQuantityForItemId(cartItemId) } .onChange(of: selectedAddonItemIds) { _, _ in quantity = currentQuantityForItemId(cartItemId) } } private func formatCurrency(_ value: Double) -> String { String(format: "R$ %.2f", value).replacingOccurrences(of: ".", with: ",") } }