import SwiftUI

// Remember to download FontSettings.swift

struct WWDC24AnimatedTextView: View {
    var text = "Hello, World!"
    var animation: Animation = .easeInOut
    var targetFontSize: CGFloat = 40
    var minimumFontSize: CGFloat = 30
    var targetFontWeight: Font.Weight = .semibold
    var minimumFontWeight: Font.Weight = .ultraLight
    var targetFontWidth: Font.Width = .expanded
    var minimumFontWidth: Font.Width = .compressed
    var delayBetweenSwitch: Double = 3
    var delayBetweenCharacter: Double = 2
    
    var toggle: Bool = false // Animation is triggered when this value is changed
    
    @StateObject private var fontSettings: FontSettings // Uses the FontSettings class
    
    init(_ text: String, toggle: Bool, animation: Animation = .easeInOut, targetFontSize: CGFloat = 40, minimumFontSize: CGFloat = 30, targetFontWeight: Font.Weight = .semibold, minimumFontWeight: Font.Weight = .ultraLight, targetFontWidth: Font.Width = .expanded, minimumFontWidth: Font.Width = .compressed, delayBetweenSwitch: Double = 3, delayBetweenCharacter: Double = 2) {
        self.text = text
        self.toggle = toggle
        self.animation = animation
        self.targetFontSize = targetFontSize
        self.minimumFontSize = minimumFontSize
        self.targetFontWeight = targetFontWeight
        self.minimumFontWeight = minimumFontWeight
        self.targetFontWidth = targetFontWidth
        self.minimumFontWidth = minimumFontWidth
        self.delayBetweenSwitch = delayBetweenSwitch
        self.delayBetweenCharacter = delayBetweenCharacter
        _fontSettings = StateObject(wrappedValue: FontSettings(text: text, targetFontSize: targetFontSize, targetFontWeight: targetFontWeight, targetFontWidth: targetFontWidth))
    }
    
    var body: some View {
        VStack {
            HStack(spacing: 0) {
                ForEach(characterIndices(text: text), id: \.index) { item in
                    Text(item.character)
                        .font(.system(size: fontSettings.fontSizes[item.index]))
                        .fontWidth(fontSettings.fontWidths[item.index])
                        .fontWeight(fontSettings.fontWeights[item.index])
                }
                .geometryGroup() // Make sure the characters are aligned when animation is playing
            }
        }
        .onChange(of: toggle) {
            toggleWholeAnimation()
        }
    }
    
    // Helper function to get characters and their indices
    func characterIndices(text: String) -> [(character: String, index: Int)] {
        var result: [(character: String, index: Int)] = []
        for (index, character) in text.enumerated() {
            result.append((String(character), index))
        }
        return result
    }
    
    // Whole bold-thin-bold animation toggle
    func toggleWholeAnimation() {
        Task {
            // First part of animation, the text will go thinner
            toggleAnimation()
            
            // Delay between two animations
            try? await Task.sleep(nanoseconds: 0_100_000_000 * UInt64(delayBetweenSwitch))
            
            // Second part of animation, the text will go to the original state
            toggleAnimation()
        }
    }
    
    // Toggle text to the opposite state
    func toggleAnimation() {
        Task {
            for index in fontSettings.fontWidths.indices {
                // Delay between each character
                try? await Task.sleep(nanoseconds: 0_100_000_000 * UInt64(delayBetweenCharacter) / UInt64(text.count))
                
                // Make text size, width and weight to the opposite
                withAnimation(animation) {
                    fontSettings.fontSizes[index] = fontSettings.fontSizes[index] == minimumFontSize ? targetFontSize : minimumFontSize
                    fontSettings.fontWidths[index] = fontSettings.fontWidths[index] == minimumFontWidth ? targetFontWidth : minimumFontWidth
                    fontSettings.fontWeights[index] = fontSettings.fontWeights[index] == minimumFontWeight ? targetFontWeight : minimumFontWeight
                }
            }
        }
    }
}