import SwiftUI
import Utilities

public struct PillButtonStyleV1: ButtonStyle {
    public struct ColorSet {
        public var foreground: Color
        public var background: Color
        public var loading: Color
        public var border: Color

        public init(foreground: Color, background: Color, loading: Color, border: Color) {
            self.foreground = foreground
            self.background = background
            self.loading = loading
            self.border = border
        }
    }

    public struct ColorCombination {
        public var enabled: ColorSet
        public var pressed: ColorSet
        public var disabled: ColorSet
        public var glassType: GlassType?

        public init(enabled: ColorSet, pressed: ColorSet, disabled: ColorSet, glassType: GlassType? = .none) {
            self.enabled = enabled
            self.pressed = pressed
            self.disabled = disabled
            self.glassType = glassType
        }
    }

    let isLoading: Bool
    let isEnabled: Bool
    let isIconOnly: Bool
    let size: PillButtonSizeV1
    let colorCombination: ColorCombination

    private var cornerRadius: CGFloat { size.borderRadius }

    public init(
    isLoading: Bool = false,
        isEnabled: Bool = true,
        isIconOnly: Bool = false,
        size: PillButtonSizeV1 = .largeRounded,
        colorCombination: ColorCombination
    ) {
        self.isLoading = isLoading
        self.isEnabled = isEnabled
        self.isIconOnly = isIconOnly
        self.size = size
        self.colorCombination = colorCombination
    }

    public func makeBody(configuration: Configuration) -> some View {
        VStack {
            configuration
                .label
                .typographyV1(size.typography)
                .opacity(isLoading ? 0 : 1)
        }
        .animation(.default, value: isLoading)
        .accentColor(colorSet(for: configuration).foreground)
        .foregroundColor(colorSet(for: configuration).foreground)
        .frame(maxWidth: size.maxWidth, minHeight: size.minHeight, alignment: size.alignment)
        .frame(width: size.width)
        .padding(size.padding)
        .background(
            RoundedRectangle(cornerRadius: cornerRadius)
                .fill(colorSet(for: configuration).background)
        )
        .overlay(
            RoundedRectangle(cornerRadius: cornerRadius)
                .stroke(colorSet(for: configuration).border)
        )
        .glassBackground(
            shape: RoundedRectangle(cornerRadius: cornerRadius),
            type: colorCombination.glassType,
            fallbackStyle: .clear
        )
        .overlay {
            ProgressView()
                .progressViewStyle(CircularProgressViewStyle(tint: colorSet(for: configuration).loading))
                .frame(width: size.minHeight / 2, height: size.minHeight / 2)
                .frame(maxWidth: size.maxWidth, alignment: size.loadingAlignment)
                .opacity(isLoading ? 1 : 0)
        }
        .contentShape(.rect)
        .scaleEffect(configuration.isPressed ? 0.985 : 1)
        .animation(.smooth(duration: 0.1), value: configuration.isPressed)
    }

    private func colorSet(for configuration: Configuration) -> ColorSet {
        if configuration.isPressed {
            return colorCombination.pressed
        } else if isEnabled {
            return colorCombination.enabled
        } else {
            return colorCombination.disabled
        }
    }
}

private struct PillButtonSizeEnvironmentKey: EnvironmentKey {
    static var defaultValue: PillButtonSizeV1 = .largeRounded
}

public extension EnvironmentValues {
    var pillButtonSizeV1: PillButtonSizeV1 {
        get { self[PillButtonSizeEnvironmentKey.self] }
        set { self[PillButtonSizeEnvironmentKey.self] = newValue }
    }
}

public extension View {
    func pillButtonSizeV1(_ size: PillButtonSizeV1) -> some View {
        environment(\.pillButtonSizeV1, size)
    }
}
