import ComponentLibrary
import SwiftUI

struct AnimationEffect: ViewModifier {
    var isSelected = true
    var id: String
    var namespace: Namespace.ID

    func body(content: Content) -> some View {
        if isSelected {
            content.matchedGeometryEffect(id: id, in: namespace)
        } else {
            content
        }
    }
}

extension View {
    func animationEffect(isSelected: Bool, id: String, in namespace: Namespace.ID) -> some View {
        modifier(AnimationEffect(isSelected: isSelected, id: id, namespace: namespace))
    }
}

enum SegmentedPickerStyle: Equatable {
    case capsule, circle
}

struct SegmentedPicker<SelectionValue, Content>: View where SelectionValue: Hashable, Content: View {
    @Namespace private var pickerTransition

    @Binding var selection: SelectionValue?

    private var items: [SelectionValue]
    private let selectionColor: Color
    private let foregroundColorSelected: Color
    private let foregroundColorNotSelected: Color
    private let style: SegmentedPickerStyle
    private let backgroundBlurOpacity: Double
    private let backgroundBlurStyle: VisualEffectView.ViewStyle
    private let backgroundFill: Color
    private let useSlideTransition: Bool

    private var content: (SelectionValue) -> Content

    // TODO: Look into making this closer to the SwiftUI `Picker` API
    init(
        selection: Binding<SelectionValue>,
        items: [SelectionValue],
        // TODO: Turn the styling into a protocol like `PickerStyle`
        selectionColor: Color = Color.SemanticV1.backgroundPrimary,
        foregroundColorSelected: Color = Color.SemanticV1.textPrimary,
        foregroundColorNotSelected: Color = Color.SemanticV1.textSecondary,
        style: SegmentedPickerStyle = .capsule,
        backgroundBlurOpacity: Double = 0.3,
        backgroundBlurStyle: VisualEffectView.ViewStyle = .dark,
        backgroundFill: Color = .clear,
        useSlideTransition: Bool = false,
        @ViewBuilder content: @escaping (SelectionValue) -> Content
    ) {
        _selection = Binding<SelectionValue?>(selection)
        self.items = items
        self.selectionColor = selectionColor
        self.foregroundColorSelected = foregroundColorSelected
        self.foregroundColorNotSelected = foregroundColorNotSelected
        self.style = style
        self.backgroundBlurOpacity = backgroundBlurOpacity
        self.backgroundBlurStyle = backgroundBlurStyle
        self.backgroundFill = backgroundFill
        self.useSlideTransition = useSlideTransition
        self.content = content
    }

    var body: some View {
        HStack(spacing: 6) {
            ForEach(items, id: \.self) { item in
                let selected = selection == item

                ZStack {
                    switch style {
                    case .capsule:
                        Capsule()
                    case .circle:
                        Circle()
                    }
                }
                .foregroundStyle(selected ? selectionColor : .clear)
                .overlay {
                    content(item)
                        .id(item)
                        .foregroundStyle(selected ? foregroundColorSelected : foregroundColorNotSelected)
                        .lineLimit(1)
                }
                .transition(.opacity)
                .modifier(if: useSlideTransition) {
                    $0.animationEffect(isSelected: selected, id: "picker", in: pickerTransition)
                }
                .frame(maxWidth: .infinity)
                .contentShape(.rect)
                .onTapGesture {
                    withAnimation(.easeInOut(duration: 0.2)) {
                        selection = item
                    }
                }
            }
            .onAppear {
                if selection == nil, let first = items.first {
                    selection = first
                }
            }
            .sensoryFeedbackIfEnabled(.selection, trigger: selection)
        }
        .padding(5)
        .background {
            VisualEffectView(style: backgroundBlurStyle)
                .background(backgroundFill)
                .clipShape(.capsule)
                .opacity(backgroundBlurOpacity)
        }
    }
}

// Native-style segmented picker that looks like our branding
struct SegmentedPickerNativeStyle<SelectionValue, Content>: View where SelectionValue: Hashable, Content: View {
    @Namespace private var pickerTransition

    @Binding var selection: SelectionValue?

    private var items: [SelectionValue]
    private let selectionColor: Color
    private let foregroundColorSelected: Color
    private let foregroundColorNotSelected: Color
    private let style: SegmentedPickerStyle
    private let backgroundBlurOpacity: Double
    private let backgroundBlurStyle: VisualEffectView.ViewStyle
    private let backgroundFill: Color
    private let useSlideTransition: Bool

    private var content: (SelectionValue) -> Content

    // TODO: Look into making this closer to the SwiftUI `Picker` API
    init(
        selection: Binding<SelectionValue>,
        items: [SelectionValue],
        // TODO: Turn the styling into a protocol like `PickerStyle`
        selectionColor: Color = Color.SemanticV1.backgroundPrimary,
        foregroundColorSelected: Color = Color.SemanticV1.textPrimary,
        foregroundColorNotSelected: Color = Color.SemanticV1.textSecondary,
        style: SegmentedPickerStyle = .capsule,
        backgroundBlurOpacity: Double = 0.3,
        backgroundBlurStyle: VisualEffectView.ViewStyle = .dark,
        backgroundFill: Color = .clear,
        useSlideTransition: Bool = false,
        @ViewBuilder content: @escaping (SelectionValue) -> Content
    ) {
        _selection = Binding<SelectionValue?>(selection)
        self.items = items
        self.selectionColor = selectionColor
        self.foregroundColorSelected = foregroundColorSelected
        self.foregroundColorNotSelected = foregroundColorNotSelected
        self.style = style
        self.backgroundBlurOpacity = backgroundBlurOpacity
        self.backgroundBlurStyle = backgroundBlurStyle
        self.backgroundFill = backgroundFill
        self.useSlideTransition = useSlideTransition
        self.content = content
    }

    var body: some View {
        HStack(spacing: 6) {
            ForEach(items, id: \.self) { item in
                let selected = selection == item

                RoundedRectangle(cornerRadius: 8)
                    .foregroundStyle(selected ? selectionColor : .clear)
                    .overlay {
                        content(item)
                            .id(item)
                            .foregroundStyle(selected ? foregroundColorSelected : foregroundColorNotSelected)
                            .lineLimit(1)
                    }
                    .transition(.opacity)
                    .animationEffect(isSelected: selected, id: "picker", in: pickerTransition)
                    .frame(maxWidth: .infinity)
                    .contentShape(.rect)
                    .onTapGesture {
                        withAnimation(.easeInOut(duration: 0.2)) {
                            selection = item
                        }
                    }
            }
            .onAppear {
                if selection == nil, let first = items.first {
                    selection = first
                }
            }
            .sensoryFeedbackIfEnabled(.selection, trigger: selection)
        }
        .padding(2)
        .background {
            VisualEffectView(style: backgroundBlurStyle)
                .background(backgroundFill)
                .clipShape(RoundedRectangle(cornerRadius: 10))
                .opacity(backgroundBlurOpacity)
        }
    }
}
