import SwiftUI

public struct MenuButtonType {
    public static var back: MenuButtonType { .init(icon: .Icon.backButtonV1) }
    public static var backCamera: MenuButtonType { .init(icon: .Icon.backCamera) }
    public static var close: MenuButtonType { .init(icon: .Icon.close) }
    public static var down: MenuButtonType { .init(icon: .Icon.arrowDown) }
    public static var more: MenuButtonType { .init(icon: .Icon.moreLarge) }
    public static var moreHorizontal: MenuButtonType { .init(icon: .Icon.moreHorizontal) }
    public static var share: MenuButtonType { .init(icon: .Icon.share) }
    public static var bars: MenuButtonType { .init(icon: .Icon.bars) }
    public static var sliders: MenuButtonType { .init(icon: .Icon.sliders) }
    public static var search: MenuButtonType { .init(icon: .Icon.search) }
    public static var notifications: MenuButtonType { .init(icon: .Icon.notifications) }
    public static var follow: MenuButtonType { .init(icon: .Icon.follow) }
    public static var settings: MenuButtonType { .init(icon: .Icon.cog) }
    public static var create: MenuButtonType { .init(icon: .Icon.plus) }
    public static var chevronDown: MenuButtonType { .init(icon: .Icon.chevronDown) }
    public static var chevronLeft: MenuButtonType { .init(icon: .Icon.chevronLeft) }
    public static var volumeOn: MenuButtonType { .init(icon: .Icon.volumeOn) }
    public static var volumeOff: MenuButtonType { .init(icon: .Icon.volumeOff) }
    public static var checkmark: MenuButtonType { .init(icon: .Icon.checkV1) }
    public static var sort: MenuButtonType { .init(icon: .Icon.sort) }
    public static var loading: MenuButtonType { .init(isLoading: true) }

    var icon: Image?
    var isLoading: Bool

    public init(icon: Image) {
        self.icon = icon
        self.isLoading = false
    }

    private init(isLoading: Bool) {
        self.icon = nil
        self.isLoading = isLoading
    }
}

@ViewBuilder public func ToolbarButton(
    _ type: MenuButtonType,
    image: Image? = nil,
    color: Color? = nil,
    glass: Bool = false,
    prominent: Bool = false,
    colorScheme: ColorScheme? = nil,
    action: @escaping () -> Void
) -> some View {
    ToolbarButton(type,
                  image: image,
                  color: color,
                  background: AnyShapeStyle?(nil),
                  glass: glass,
                  prominent: prominent,
                  colorScheme: colorScheme,
                  action: action)
}

@ViewBuilder public func ToolbarButton<S>(
    _ type: MenuButtonType,
    image: Image? = nil,
    color: Color? = nil,
    background: S? = AnyShapeStyle?(nil),
    glass: Bool = false,
    prominent: Bool = false,
    colorScheme: ColorScheme? = nil,
    action: @escaping () -> Void
) -> some View where S: ShapeStyle {
    ToolbarButtonView(image: image ?? type.icon,
                      color: color ?? Color.SemanticV1.iconPrimary,
                      background: background,
                      prominent: prominent,
                      glass: glass,
                      colorScheme: colorScheme,
                      isLoading: type.isLoading,
                      action: action)
}

private struct ToolbarButtonView<S>: View where S: ShapeStyle {
    private let image: Image?
    private let color: Color
    private let background: S?
    private let prominent: Bool
    private let glass: Bool
    private let colorScheme: ColorScheme?
    private let action: () -> Void
    private let isLoading: Bool

    init(
        image: Image?,
        color: Color = Color.SemanticV1.iconPrimary,
        background: S? = Material.ultraThin,
        prominent: Bool = false,
        glass: Bool = false,
        colorScheme: ColorScheme? = nil,
        isLoading: Bool = false,
        action: @escaping () -> Void
    ) {
        self.image = image
        self.color = color
        self.background = background
        self.prominent = prominent
        self.glass = glass
        self.colorScheme = colorScheme
        self.isLoading = isLoading
        self.action = action
    }

    @Environment(\.colorScheme) var environmentColorScheme

    private var label: some View {
        Group {
            if isLoading {
                ProgressView()
                    .progressViewStyle(.circular)
                    .frame(width: 24, height: 24)
                    .tint(color)
            } else if let image {
                image
                    .aspectRatio(1.0, contentMode: .fit)
                    .foregroundStyle(color)
            }
        }
    }

    var body: some View {
        if #available(iOS 26.0, *) {
            button
        } else {
            oldButton
        }
    }

    @available(iOS 26.0, *)
    @ViewBuilder
    var button: some View {
        if glass && prominent, let background, let color = background as? Color {
            Button(action: tap) {
                label
                    .frame(width: 40, height: 40)
                    .padding(2)
            }
            .glassEffect(.regular.interactive().tint(color))
        } else if glass {
            Button(action: tap) {
                label
                    .frame(width: 40, height: 40)
                    .padding(2)
            }
            .glassEffect(.regular.interactive())
        } else if prominent {
            Button(action: tap) { label }
                .buttonStyle(.borderedProminent)
                .tint(background)
        } else {
            Button(action: tap) { label }
        }
    }

    var oldButton: some View {
        Button(action: tap) {
            label
                .frame(width: 40, height: 40)
                .padding(2)
                .background {
                    if let background = background {
                        Circle().fill(background)
                    }
                }
                .clipShape(Rectangle())
                .padding(4)
        }
        .buttonStyle(.plain)
        .environment(\.colorScheme, colorScheme ?? environmentColorScheme)
    }

    private func tap() {
        UIImpactFeedbackGenerator(style: .light).impactOccurred()
        action()
    }
}

struct ToolbarButton_Previews: PreviewProvider {
    static var previews: some View {
        ToolbarButtonSample()
    }
}

struct ToolbarButtonSample: View {
    var body: some View {
        VStack(spacing: 20) {
            ToolbarButton(.close) {}
            ToolbarButton(.back) {}
            ToolbarButton(.loading) {}
        }
        .padding()
    }
}
