import Foundation import SwiftUI extension PizzaProductDetailSheet { var stepSizes: some View { let sizeItems = sizes return VStack(alignment: .leading, spacing: 10) { Text("1. Tamanho") .font(AppTypography.heading3) .foregroundStyle(AppColors.textPrimary) ForEach(Array(sizeItems.indices), id: \.self) { index in sizeRow(sizeItems[index]) } } .padding(12) .background(AppColors.surface) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) } var stepDoughs: some View { VStack(alignment: .leading, spacing: 10) { Text("2. Massa") .font(AppTypography.heading3) .foregroundStyle(AppColors.textPrimary) if doughs.count <= 1 { Text(doughs.first?.name ?? "Massa tradicional") .font(AppTypography.body) .foregroundStyle(AppColors.textPrimary) } else { ForEach(doughs) { dough in radioRow( title: dough.name ?? "Massa", subtitle: nil, isSelected: selectedDoughId == dough.id ) { selectedDoughId = dough.id } } } } .padding(12) .background(AppColors.surface) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) } var stepCrusts: some View { VStack(alignment: .leading, spacing: 10) { Text("3. Borda") .font(AppTypography.heading3) .foregroundStyle(AppColors.textPrimary) if crusts.count <= 1 { Text(crustDescription(crusts.first)) .font(AppTypography.body) .foregroundStyle(AppColors.textPrimary) } else { ForEach(crusts) { crust in radioRow( title: crust.name ?? "Borda", subtitle: crust.priceModifier ?? 0 > 0 ? "+ \(formatCurrency(crust.priceModifier ?? 0))" : nil, isSelected: selectedCrustId == crust.id ) { selectedCrustId = crust.id } } } } .padding(12) .background(AppColors.surface) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) } var stepFlavors: some View { let flavorItems = flavors return VStack(alignment: .leading, spacing: 10) { Text("4. Sabores (\(selectedFlavorIds.count)/\(maxFlavorsAllowed))") .font(AppTypography.heading3) .foregroundStyle(AppColors.textPrimary) Text("Toque no sabor para escolher adicionais.") .font(.caption) .foregroundStyle(AppColors.textMuted) ForEach(Array(flavorItems.indices), id: \.self) { index in let flavor = flavorItems[index] let isSelected = selectedFlavorIds.contains(flavor.id) let price = selectedSizeId.flatMap { flavor.pizzaPrices[$0] } ?? flavor.price let maxReached = selectedFlavorIds.count >= maxFlavorsAllowed let disableSwitch = isSelected == false && maxReached HStack(spacing: 10) { VStack(alignment: .leading, spacing: 4) { Text(flavor.name) .font(AppTypography.body) .foregroundStyle(AppColors.textPrimary) if let price { Text(formatCurrency(price)) .font(.caption) .foregroundStyle(AppColors.textMuted) } } Spacer() Toggle("", isOn: Binding( get: { isSelected }, set: { value in if value { addFlavor(flavor.id) } else { removeFlavor(flavor.id) } } )) .labelsHidden() .disabled(disableSwitch) } .padding(.vertical, 2) .contentShape(Rectangle()) .onTapGesture { guard isSelected else { return } guard flavor.addonGroups.contains(where: { $0.items.isEmpty == false }) else { return } selectedFlavorForAddons = flavor } } } .padding(12) .background(AppColors.surface) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) } func sizeRow(_ size: StorePizzaSize) -> some View { let title = size.name ?? "Tamanho" let subtitle = "Até \(max(1, size.maxFlavors ?? 1)) sabor(es)" let selected = selectedSizeId == size.id return radioRow( title: title, subtitle: subtitle, isSelected: selected ) { selectedSizeId = size.id } } func radioRow(title: String, subtitle: String?, isSelected: Bool, action: @escaping () -> Void) -> some View { Button(action: action) { HStack(spacing: 10) { ZStack { Circle() .stroke(isSelected ? AppColors.primary : AppColors.textMuted.opacity(0.4), lineWidth: 2) .frame(width: 20, height: 20) if isSelected { Circle() .fill(AppColors.primary) .frame(width: 10, height: 10) } } VStack(alignment: .leading, spacing: 2) { Text(title) .font(AppTypography.body) .foregroundStyle(AppColors.textPrimary) if let subtitle, subtitle.isEmpty == false { Text(subtitle) .font(.caption) .foregroundStyle(AppColors.textMuted) } } Spacer() } .contentShape(Rectangle()) } .buttonStyle(.plain) } func crustDescription(_ crust: StorePizzaCrust?) -> String { guard let crust else { return "Sem borda especial" } let name = crust.name ?? "Borda" let modifier = crust.priceModifier ?? 0 if modifier > 0 { return "\(name) (+ \(formatCurrency(modifier)))" } return name } func applyAutoSelections() { if selectedSizeId != nil { if doughs.count == 1 { selectedDoughId = doughs.first?.id } else if doughs.isEmpty { selectedDoughId = "__none__" } } if isDoughReady { if crusts.count == 1 { selectedCrustId = crusts.first?.id } else if crusts.isEmpty { selectedCrustId = "__none__" } } } func trimFlavorSelectionByLimit() { let limit = maxFlavorsAllowed guard selectedFlavorIds.count > limit else { return } let sorted = selectedFlavorIds.sorted() selectedFlavorIds = Set(sorted.prefix(limit)) } func addFlavor(_ flavorId: String) { if selectedFlavorIds.contains(flavorId) { return } if selectedFlavorIds.count >= maxFlavorsAllowed { return } selectedFlavorIds.insert(flavorId) } func removeFlavor(_ flavorId: String) { selectedFlavorIds.remove(flavorId) flavorAddonQuantities.removeValue(forKey: flavorId) } func formatCurrency(_ value: Double) -> String { String(format: "R$ %.2f", value).replacingOccurrences(of: ".", with: ",") } }