import SwiftUI
import CoreMotion

/// A floating artwork view with blur, opacity, and gyroscope parallax effects
struct FloatingArtwork: View {
    let imageName: String
    let size: CGFloat
    let cornerRadius: CGFloat
    let rotation: Double
    let offsetX: CGFloat
    let offsetY: CGFloat
    let blurRadius: CGFloat
    let opacity: Double
    let parallaxMultiplier: Double // How much the gyroscope affects this artwork
    let floatDuration: Double // Duration for floating animation
    let floatDelay: Double // Delay before animation starts

    @Binding var gyroscopeOffset: CGSize
    @State private var floatingOffset: CGSize = .zero

    var body: some View {
        Image(imageName)
            .resizable()
            .aspectRatio(contentMode: .fill)
            .frame(width: size, height: size)
            .clipShape(RoundedRectangle(cornerRadius: cornerRadius))
            .blur(radius: blurRadius)
            .opacity(opacity)
            .rotationEffect(.degrees(rotation))
            .offset(
                x: offsetX + (gyroscopeOffset.width * parallaxMultiplier) + floatingOffset.width,
                y: offsetY + (gyroscopeOffset.height * parallaxMultiplier) + floatingOffset.height
            )
            .onAppear {
                startFloatingAnimation()
            }
    }

    private func startFloatingAnimation() {
        // Create a subtle floating effect with different phases for each artwork
        withAnimation(
            .easeInOut(duration: floatDuration)
            .repeatForever(autoreverses: true)
            .delay(floatDelay)
        ) {
            floatingOffset = CGSize(
                width: CGFloat.random(in: -8...8),
                height: CGFloat.random(in: -12...12)
            )
        }
    }
}

/// Manager for handling device motion (gyroscope) data
class MotionManager: ObservableObject {
    private var motionManager: CMMotionManager
    @Published var offset: CGSize = .zero

    private let maxOffset: CGFloat = 20 // Maximum pixel offset from gyroscope

    init() {
        self.motionManager = CMMotionManager()
        self.motionManager.deviceMotionUpdateInterval = 1/60 // 60 FPS
    }

    func startUpdates() {
        guard motionManager.isDeviceMotionAvailable else { return }

        motionManager.startDeviceMotionUpdates(to: .main) { [weak self] motion, error in
            guard let motion = motion, let self = self else { return }

            // Use gravity to determine device tilt
            // Gravity x: -1 to 1 (left to right)
            // Gravity y: -1 to 1 (bottom to top)
            let x = motion.gravity.x
            let y = motion.gravity.y

            // Convert to offset (invert for natural parallax)
            self.offset = CGSize(
                width: CGFloat(-x) * self.maxOffset,
                height: CGFloat(y) * self.maxOffset
            )
        }
    }

    func stopUpdates() {
        motionManager.stopDeviceMotionUpdates()
    }

    deinit {
        stopUpdates()
    }
}

/// Container view for all floating artworks with gyroscope support and typing animation
struct FloatingArtworksBackground: View {
    @StateObject private var motionManager = MotionManager()
    @State private var currentTextIndex: Int = 0
    @State private var displayedText: String = ""
    @State private var characterOpacities: [Double] = []
    @State private var isTyping: Bool = false
    @State private var isKeyboardVisible: Bool = false

    // Fixed artwork images from Assets/Artwork folder
    private let artworkImages: [String] = [
        "Artwork/1",
        "Artwork/2",
        "Artwork/3",
        "Artwork/4"
    ]

    private let textOptions = [
        "Make any song you can imagine",
        "Make a jazz song about watering my plants",
        "Make a house song about quitting your job",
        "Make a country song about Jess being late"
    ]

    var body: some View {
        ZStack {
            // Large artwork - top left, rotated -30 degrees
            FloatingArtwork(
                imageName: artworkImages[3],
                size: 195,
                cornerRadius: 32.276,
                rotation: -30,
                offsetX: -200,
                offsetY: -120,
                blurRadius: 3,
                opacity: 0.8,
                parallaxMultiplier: 1.5,
                floatDuration: 4.5,
                floatDelay: 0.0,
                gyroscopeOffset: $motionManager.offset
            )

            // Medium artwork - top right
            FloatingArtwork(
                imageName: artworkImages[2],
                size: 115,
                cornerRadius: 24,
                rotation: 0,
                offsetX: 80,
                offsetY: -150,
                blurRadius: 4,
                opacity: 0.5,
                parallaxMultiplier: 1.2,
                floatDuration: 3.8,
                floatDelay: 0.8,
                gyroscopeOffset: $motionManager.offset
            )

            // Small artwork - middle left
            FloatingArtwork(
                imageName: artworkImages[1],
                size: 86,
                cornerRadius: 24,
                rotation: 0,
                offsetX: -80,
                offsetY: 155,
                blurRadius: 6,
                opacity: 0.3,
                parallaxMultiplier: 1.0,
                floatDuration: 5.2,
                floatDelay: 1.5,
                gyroscopeOffset: $motionManager.offset
            )

            // Large artwork - bottom right, rotated 15 degrees
            FloatingArtwork(
                imageName: artworkImages[0],
                size: 195,
                cornerRadius: 32.276,
                rotation: 15,
                offsetX: 200,
                offsetY: 150,
                blurRadius: 1,
                opacity: 0.6,
                parallaxMultiplier: 1.5,
                floatDuration: 4.2,
                floatDelay: 0.5,
                gyroscopeOffset: $motionManager.offset
            )

            // Centered typing animation headline with fade-in per character
            if !isKeyboardVisible {
                VStack(spacing: 0) {
                    // Create attributed text with individual character opacities
                    createFadedText()
                        .lineLimit(3)
                        .multilineTextAlignment(.center)
                        .fixedSize(horizontal: false, vertical: true)
                }
                .frame(width: 250)
                .transition(.opacity)
            }
        }
        .onAppear {
            motionManager.startUpdates()
            startTypingAnimation()
            setupKeyboardObservers()
        }
        .onDisappear {
            motionManager.stopUpdates()
            removeKeyboardObservers()
        }
    }

    private func createFadedText() -> Text {
        var result = Text("")

        // Get the full text to maintain consistent layout
        let fullText = textOptions[currentTextIndex]

        // Add each character with its opacity (visible or invisible)
        for (index, character) in fullText.enumerated() {
            let opacity = index < displayedText.count ?
                (index < characterOpacities.count ? characterOpacities[index] : 0) : 0
            let charText = Text(String(character))
                .font(.custom("PP Neue Montreal", size: 28).weight(.medium))
                .foregroundColor(.white.opacity(opacity))
                .tracking(0.48)
            result = result + charText
        }

        return result
    }

    private func startTypingAnimation() {
        typeText()
    }

    private func typeText() {
        let currentText = textOptions[currentTextIndex]
        displayedText = ""
        characterOpacities = []
        isTyping = true

        // Type out the current text with fade-in effect
        for (index, character) in currentText.enumerated() {
            DispatchQueue.main.asyncAfter(deadline: .now() + Double(index) * 0.025) {
                displayedText.append(character)
                characterOpacities.append(0)

                // Fade in the new character quickly
                withAnimation(.easeIn(duration: 0.15)) {
                    if characterOpacities.count > 0 {
                        characterOpacities[characterOpacities.count - 1] = 1.0
                    }
                }

                // If this is the last character
                if index == currentText.count - 1 {
                    isTyping = false
                    // Wait 3 seconds before starting to delete
                    DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
                        deleteText()
                    }
                }
            }
        }
    }

    private func deleteText() {
        let currentText = displayedText

        // Delete the text character by character with fade-out
        for index in 0..<currentText.count {
            DispatchQueue.main.asyncAfter(deadline: .now() + Double(index) * 0.015) {
                // Fade out the last visible character
                let charIndexToFade = currentText.count - index - 1
                if charIndexToFade < characterOpacities.count {
                    withAnimation(.easeOut(duration: 0.1)) {
                        characterOpacities[charIndexToFade] = 0
                    }
                }

                // Update displayed text
                displayedText = String(currentText.dropLast(index + 1))

                // If this is the last character to delete
                if index == currentText.count - 1 {
                    // Move to next text and start typing again
                    currentTextIndex = (currentTextIndex + 1) % textOptions.count
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                        typeText()
                    }
                }
            }
        }
    }

    private func setupKeyboardObservers() {
        NotificationCenter.default.addObserver(
            forName: UIResponder.keyboardWillShowNotification,
            object: nil,
            queue: .main
        ) { _ in
            withAnimation(.easeOut(duration: 0.25)) {
                isKeyboardVisible = true
            }
        }

        NotificationCenter.default.addObserver(
            forName: UIResponder.keyboardWillHideNotification,
            object: nil,
            queue: .main
        ) { _ in
            withAnimation(.easeIn(duration: 0.25)) {
                isKeyboardVisible = false
            }
        }
    }

    private func removeKeyboardObservers() {
        NotificationCenter.default.removeObserver(
            self,
            name: UIResponder.keyboardWillShowNotification,
            object: nil
        )
        NotificationCenter.default.removeObserver(
            self,
            name: UIResponder.keyboardWillHideNotification,
            object: nil
        )
    }
}

#Preview {
    ZStack {
        Constants.Colors.Background.primary
            .ignoresSafeArea()

        FloatingArtworksBackground()
    }
}
