import SwiftUI

public struct GradientSpinner: View {
    public enum Size {
        case small
        case medium
        case large
        case extraLarge
        case custom(width: CGFloat, height: CGFloat, lineWidth: CGFloat)

        var dimensions: (width: CGFloat, height: CGFloat, lineWidth: CGFloat) {
            switch self {
            case .small:
                return (12, 12, 2.5)
            case .medium:
                return (16, 16, 3.5)
            case .large:
                return (20, 20, 4.5)
            case .extraLarge:
                return (24, 24, 5)
            case let .custom(width, height, lineWidth):
                return (width, height, lineWidth)
            }
        }
    }

    private let size: Size
    private let startColor: Color
    private let endColor: Color

    @State private var rotation = 0.0

    public init(size: Size = .medium, startColor: Color, endColor: Color) {
        self.size = size
        self.startColor = startColor
        self.endColor = endColor
    }

    public init(size: Size = .medium, color: Color = Color.SemanticV1.textPrimary) {
        self.size = size
        self.startColor = color.opacity(0)
        self.endColor = color
    }

    // MARK: - Spinner View
    private var spinnerView: some View {
        let dimensions = size.dimensions

        return Canvas { context, canvasSize in
            let center = CGPoint(x: canvasSize.width / 2, y: canvasSize.height / 2)
            let radius = min(canvasSize.width, canvasSize.height) / 2 - dimensions.lineWidth / 2

            let path = Path { path in
                path.addArc(
                    center: center,
                    radius: radius,
                    startAngle: .degrees(0),
                    endAngle: .degrees(360),
                    clockwise: false
                )
            }

            let gradient = Gradient(stops: [
                .init(color: startColor.opacity(0), location: 0.0),
                .init(color: endColor, location: 1.0),
            ])

            context.stroke(
                path,
                with: .conicGradient(
                    gradient,
                    center: center,
                    angle: .degrees(0)
                ),
                lineWidth: dimensions.lineWidth
            )
        }
        .frame(width: dimensions.width, height: dimensions.height)
    }

    // MARK: - Body
    public var body: some View {
        spinnerView
            .rotationEffect(.degrees(rotation))
            .onAppear {
                withAnimation(.linear(duration: 1).repeatForever(autoreverses: false)) {
                    rotation = 360
                }
            }
            .onDisappear {
                rotation = 0
            }
    }
}

#Preview {
    VStack(spacing: 20) {
        HStack(spacing: 20) {
            VStack {
                GradientSpinner(size: .small)
                Text("Small").font(.caption)
            }

            VStack {
                GradientSpinner(size: .medium)
                Text("Medium").font(.caption)
            }

            VStack {
                GradientSpinner(size: .large)
                Text("Large").font(.caption)
            }

            VStack {
                GradientSpinner(size: .extraLarge)
                Text("Extra Large").font(.caption)
            }
        }

        Text("GradientSpinner Size Variants")
            .font(.headline)
    }
    .padding()
}
