//
//  AnimationUtilities.swift
//  lichunWebsocket
//
//  Reusable animation patterns and utilities
//

import SwiftUI

// MARK: - Animation Constants
struct AppAnimations {
    // MARK: - Timing
    /// Quick, snappy animation for immediate feedback
    static let quick = Animation.spring(response: 0.2, dampingFraction: 0.75)

    /// Standard animation for most interactions
    static let standard = Animation.spring(response: 0.25, dampingFraction: 0.8)

    /// Gentle, smooth animation for larger transitions
    static let gentle = Animation.spring(response: 0.3, dampingFraction: 0.75)

    /// Bouncy animation for playful interactions
    static let bounce = Animation.spring(response: 0.35, dampingFraction: 0.6)

    // MARK: - Easing
    /// Standard ease in-out for smooth transitions
    static let easeInOut = Animation.easeInOut(duration: 0.2)

    /// Ease out for elements entering the screen
    static let easeOut = Animation.easeOut(duration: 0.15)

    /// Ease in for elements leaving the screen
    static let easeIn = Animation.easeIn(duration: 0.15)

    // MARK: - Special
    /// Shimmer effect for loading states
    static let shimmer = Animation.linear(duration: 1.5).repeatForever(autoreverses: false)

    /// Pulse animation for attention-grabbing elements
    static let pulse = Animation.easeInOut(duration: 1.0).repeatForever(autoreverses: true)
}

// MARK: - Button Style with Animation
struct ScaleButtonStyle: ButtonStyle {
    let scaleAmount: CGFloat
    let hapticEnabled: Bool

    init(scaleAmount: CGFloat = 0.95, hapticEnabled: Bool = true) {
        self.scaleAmount = scaleAmount
        self.hapticEnabled = hapticEnabled
    }

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .scaleEffect(configuration.isPressed ? scaleAmount : 1.0)
            .animation(AppAnimations.quick, value: configuration.isPressed)
            .onChange(of: configuration.isPressed) { isPressed in
                if isPressed && hapticEnabled {
                    hapticFeedback(style: .light)
                }
            }
    }
}

extension View {
    /// Add scale-on-tap animation to any view
    func scaleOnTap(amount: CGFloat = 0.95, haptic: Bool = true) -> some View {
        self.buttonStyle(ScaleButtonStyle(scaleAmount: amount, hapticEnabled: haptic))
    }
}

// MARK: - Count Up Animation
struct CountUpText: View {
    let targetValue: Int
    let formatter: NumberFormatter?
    @State private var displayValue: Double = 0

    init(targetValue: Int, formatter: NumberFormatter? = nil) {
        self.targetValue = targetValue
        self.formatter = formatter
    }

    var body: some View {
        Text(formattedValue)
            .onAppear {
                withAnimation(.easeOut(duration: 1.0)) {
                    displayValue = Double(targetValue)
                }
            }
            .onChange(of: targetValue) { newValue in
                withAnimation(.easeOut(duration: 0.5)) {
                    displayValue = Double(newValue)
                }
            }
    }

    private var formattedValue: String {
        let value = Int(displayValue)
        if let formatter = formatter {
            return formatter.string(from: NSNumber(value: value)) ?? "\(value)"
        }
        return "\(value)"
    }
}

// MARK: - Shake Animation
struct ShakeEffect: GeometryEffect {
    var amount: CGFloat = 10
    var shakesPerUnit = 3
    var animatableData: CGFloat

    func effectValue(size: CGSize) -> ProjectionTransform {
        ProjectionTransform(CGAffineTransform(translationX:
            amount * sin(animatableData * .pi * CGFloat(shakesPerUnit)),
            y: 0))
    }
}

extension View {
    /// Shake animation triggered by a changing value
    func shake(trigger: Int) -> some View {
        self.modifier(ShakeEffect(animatableData: CGFloat(trigger)))
    }
}

// MARK: - Shimmer Effect
struct ShimmerModifier: ViewModifier {
    @State private var phase: CGFloat = 0
    let duration: Double
    let bounce: Bool

    init(duration: Double = 1.5, bounce: Bool = false) {
        self.duration = duration
        self.bounce = bounce
    }

    func body(content: Content) -> some View {
        content
            .overlay(
                GeometryReader { geometry in
                    Rectangle()
                        .fill(
                            LinearGradient(
                                gradient: Gradient(colors: [
                                    Color.white.opacity(0),
                                    Color.white.opacity(0.3),
                                    Color.white.opacity(0)
                                ]),
                                startPoint: .leading,
                                endPoint: .trailing
                            )
                        )
                        .offset(x: geometry.size.width * (phase - 1))
                        .frame(width: geometry.size.width)
                }
            )
            .mask(content)
            .onAppear {
                withAnimation(
                    Animation.linear(duration: duration)
                        .repeatForever(autoreverses: bounce)
                ) {
                    phase = 1
                }
            }
    }
}

extension View {
    /// Add shimmer effect for loading states
    func shimmer(duration: Double = 1.5, bounce: Bool = false) -> some View {
        self.modifier(ShimmerModifier(duration: duration, bounce: bounce))
    }
}

// MARK: - Pulse Effect
struct PulseModifier: ViewModifier {
    @State private var isPulsing = false
    let minScale: CGFloat
    let maxScale: CGFloat
    let duration: Double

    init(minScale: CGFloat = 0.9, maxScale: CGFloat = 1.1, duration: Double = 1.0) {
        self.minScale = minScale
        self.maxScale = maxScale
        self.duration = duration
    }

    func body(content: Content) -> some View {
        content
            .scaleEffect(isPulsing ? maxScale : minScale)
            .onAppear {
                withAnimation(
                    Animation.easeInOut(duration: duration)
                        .repeatForever(autoreverses: true)
                ) {
                    isPulsing = true
                }
            }
    }
}

extension View {
    /// Add pulse animation for attention-grabbing elements
    func pulse(minScale: CGFloat = 0.95, maxScale: CGFloat = 1.05, duration: Double = 1.0) -> some View {
        self.modifier(PulseModifier(minScale: minScale, maxScale: maxScale, duration: duration))
    }
}

// MARK: - Slide Transition
enum SlideDirection {
    case leading, trailing, top, bottom

    var edge: Edge {
        switch self {
        case .leading: return .leading
        case .trailing: return .trailing
        case .top: return .top
        case .bottom: return .bottom
        }
    }
}

extension View {
    /// Slide in/out from a specific direction
    func slideTransition(_ direction: SlideDirection, animation: Animation = AppAnimations.standard) -> some View {
        self.transition(.move(edge: direction.edge))
    }
}

// MARK: - Rotate Effect
struct RotateEffect: ViewModifier {
    @State private var isRotating = false
    let duration: Double

    init(duration: Double = 1.0) {
        self.duration = duration
    }

    func body(content: Content) -> some View {
        content
            .rotationEffect(.degrees(isRotating ? 360 : 0))
            .onAppear {
                withAnimation(
                    Animation.linear(duration: duration)
                        .repeatForever(autoreverses: false)
                ) {
                    isRotating = true
                }
            }
    }
}

extension View {
    /// Continuous rotation animation
    func rotate(duration: Double = 1.0) -> some View {
        self.modifier(RotateEffect(duration: duration))
    }
}
