//
//  AccessibilityHelpers.swift
//  Reflect
//
//  Accessibility utilities for supporting VoiceOver, Dynamic Type, and Reduce Motion.
//

import SwiftUI

// MARK: - Reduce Motion Support

/// Environment key for accessing reduce motion preference
struct ReduceMotionKey: EnvironmentKey {
    static let defaultValue: Bool = false
}

extension EnvironmentValues {
    var reduceMotion: Bool {
        get { self[ReduceMotionKey.self] }
        set { self[ReduceMotionKey.self] = newValue }
    }
}

extension View {
    /// Wraps content in withAnimation respecting reduce motion
    func withAccessibleAnimation<V: Equatable>(_ animation: Animation? = .default, value: V, action: @escaping () -> Void) -> some View {
        self.onChange(of: value) { _, _ in
            if UIAccessibility.isReduceMotionEnabled {
                action()
            } else {
                withAnimation(animation) {
                    action()
                }
            }
        }
    }
}

// MARK: - Accessibility Helpers

extension View {
    /// Adds accessibility label with optional hint
    func accessibleMoodCell(mood: Mood, date: Date) -> some View {
        let dateString = DateFormattingCache.shared.string(for: date, format: .dateMedium)

        return self
            .accessibilityLabel("\(mood.strValue) on \(dateString)")
            .accessibilityHint("Double tap to edit mood")
    }

    /// Makes a button accessible with custom label
    func accessibleButton(label: String, hint: String? = nil) -> some View {
        self
            .accessibilityLabel(label)
            .accessibilityHint(hint ?? "")
            .accessibilityAddTraits(.isButton)
    }

    /// Groups related elements for VoiceOver
    func accessibilityGrouped(label: String) -> some View {
        self
            .accessibilityElement(children: .combine)
            .accessibilityLabel(label)
    }
}

// MARK: - Dynamic Type Support

extension Font {
    /// Returns a scalable font that respects Dynamic Type
    static func scalable(_ style: Font.TextStyle, weight: Font.Weight = .regular) -> Font {
        Font.system(style, design: .rounded).weight(weight)
    }
}

/// Property wrapper for scaled metrics that respect Dynamic Type
@propertyWrapper
struct ScaledValue: DynamicProperty {
    @ScaledMetric private var scaledValue: CGFloat

    var wrappedValue: CGFloat { scaledValue }

    init(wrappedValue: CGFloat, relativeTo textStyle: Font.TextStyle = .body) {
        _scaledValue = ScaledMetric(wrappedValue: wrappedValue, relativeTo: textStyle)
    }
}

extension View {
    /// Ensures minimum touch target size for accessibility (44x44 points)
    func accessibleTouchTarget() -> some View {
        self.frame(minWidth: 44, minHeight: 44)
    }
}

// MARK: - Accessibility Announcements

struct AccessibilityAnnouncement {
    /// Announces a message to VoiceOver users
    static func announce(_ message: String) {
        UIAccessibility.post(notification: .announcement, argument: message)
    }

    /// Notifies VoiceOver that screen content has changed
    static func screenChanged() {
        UIAccessibility.post(notification: .screenChanged, argument: nil)
    }

    /// Notifies VoiceOver that layout has changed
    static func layoutChanged(focusElement: Any? = nil) {
        UIAccessibility.post(notification: .layoutChanged, argument: focusElement)
    }
}

// MARK: - Reduce Motion View Modifier

/// View modifier that provides alternative content when Reduce Motion is enabled
struct ReduceMotionContent<Reduced: View>: ViewModifier {
    @Environment(\.accessibilityReduceMotion) private var reduceMotion
    let reducedContent: () -> Reduced

    func body(content: Content) -> some View {
        if reduceMotion {
            reducedContent()
        } else {
            content
        }
    }
}

extension View {
    /// Provides alternative content when Reduce Motion is enabled
    func reduceMotionAlternative<V: View>(@ViewBuilder _ reduced: @escaping () -> V) -> some View {
        modifier(ReduceMotionContent(reducedContent: reduced))
    }

    /// Conditionally applies animation based on Reduce Motion setting
    func animationIfAllowed<V: Equatable>(_ animation: Animation?, value: V) -> some View {
        modifier(ConditionalAnimationModifier(animation: animation, value: value))
    }
}

struct ConditionalAnimationModifier<V: Equatable>: ViewModifier {
    @Environment(\.accessibilityReduceMotion) private var reduceMotion
    let animation: Animation?
    let value: V

    func body(content: Content) -> some View {
        if reduceMotion {
            content
        } else {
            content.animation(animation, value: value)
        }
    }
}

// MARK: - VoiceOver Detection

extension View {
    /// Runs an action when VoiceOver is running
    func onVoiceOverChange(perform action: @escaping (Bool) -> Void) -> some View {
        self.onReceive(NotificationCenter.default.publisher(for: UIAccessibility.voiceOverStatusDidChangeNotification)) { _ in
            action(UIAccessibility.isVoiceOverRunning)
        }
        .onAppear {
            action(UIAccessibility.isVoiceOverRunning)
        }
    }
}
