//
//  SwipeFeedView.swift
//  Suno
//
//  Created by Martin Camacho on 3/15/24.
//

import Foundation
import SwiftUI


enum PresentationState: Hashable {
    case presented
    case dismissed
}

struct PresentationStateKey: EnvironmentKey {
    static var defaultValue = PresentationState.dismissed
}

extension EnvironmentValues {
    var presentationState: PresentationState {
        get { self[PresentationStateKey.self] }
        set { self[PresentationStateKey.self] = newValue }
    }
}

struct PresentationStateChangeModifier: ViewModifier {
    // callback will fire when state changes to detectState
    let detectState: PresentationState
    
    let callback: () -> Void
    
    @Environment(\.presentationState) var state
    
    func body(content: Content) -> some View {
        content.onChange(of: state) { _, newValue in
            if newValue == detectState {
                callback()
            }
        }
    }
}

extension View {
    func onPresented(action: @escaping () -> Void) -> some View {
        modifier(PresentationStateChangeModifier(detectState: .presented, callback: action))
    }
    
    func onDismissed(action: @escaping () -> Void) -> some View {
        modifier(PresentationStateChangeModifier(detectState: .dismissed, callback: action))
    }
}

// Helper function to determine top padding based on safe area
private func safeAreaTopPadding() -> CGFloat {
    // Get the current window's safe area insets
    let window = UIApplication.shared.windows.first { $0.isKeyWindow }
    let safeAreaTopInset = window?.safeAreaInsets.top ?? 0
    return safeAreaTopInset > 20 ? safeAreaTopInset : 20 // Return the safe area inset, or a minimum value to ensure padding
}

struct SomeView: View {
    
    let item: Clip
    @EnvironmentObject var playerViewModel: PlayerViewModel
    
    var body: some View {
        ZStack {
            Rectangle()
                .fill(Color.red.opacity(0.6))
                .containerRelativeFrame([.horizontal, .vertical])
            VStack {
                Text(item.title ?? "")
                    .font(.title)
                    .bold()
                if let urlString = item.imageUrl, let imageUrl = URL(string: urlString) {
                    AsyncImage(url: imageUrl) { image in
                        image.resizable()
                    } placeholder: {
                        ProgressView() // Show a progress indicator while loading
                    }
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .aspectRatio(contentMode: .fit)
                    .clipped()
                    .cornerRadius(10)
                    .padding(20)
                }
                Spacer()
            }
            .padding(.top, safeAreaTopPadding())
        }
        .onPresented {
            print("Presented \(item.title)")
            playerViewModel.playClip(clip: item)
        }
        .onDismissed {
            print("Dismissed \(item.title)")
        }
    }
}

class SwipeFeedViewModel: ObservableObject {
    @Published var items = [Clip]()
    
    
    var clipsCallback: () async throws -> [Clip]
    private var timer: Timer?
    
    private var networkManager: NetworkManager = NetworkManager()
    
    init(clipsCallback: @escaping () async throws  -> [Clip]) {
        self.clipsCallback = clipsCallback
    }
    
    
    func load() {
        Task { [weak self] in
            do {
                let items = try await clipsCallback()
                DispatchQueue.main.async {
                    print("Loading swipe feed items", items.count)
                    self?.items = items
                }
            } catch {
                // Handle any errors, such as logging them or showing an error message
                print("Error fetching data: \(error.localizedDescription)")
            }
        }
    }
    
    func onAppear() {
        self.load()
//        timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { [weak self] _ in
//            self?.load()
//        }
    }
    
    func onDisappear() {
        timer?.invalidate()
        timer = nil
    }
    
    func addMore() {
        items.append(items[0])
    }
    
    deinit {
        // Invalidate the timer if the view model is deinitialized
        onDisappear()
    }
}


struct SwipeFeedView: View {
    
    @StateObject var viewModel = SwipeFeedViewModel(
        clipsCallback: NetworkManager().fetchData2
    )
    @EnvironmentObject var playerViewModel: PlayerViewModel
    @State var currentClipId: Int?
    
    var body: some View {
        ScrollView(.vertical, showsIndicators: false) {
            LazyVStack(spacing: 0) {
                ForEach(Array(zip(viewModel.items.indices, viewModel.items)), id: \.0) { index, item in
                   SomeView(item: item)
                        .environment(\.presentationState, index == currentClipId ? .presented : .dismissed)
                        .id(index)
                }
            }
            .scrollTargetLayout()
        }

        .scrollTargetBehavior(.paging)
        .scrollPosition(id: $currentClipId, anchor: .center)
        .ignoresSafeArea()
        .onChange(of: currentClipId) { oldId, newId in
            print("change \(oldId) \(newId)")
            if newId == viewModel.items.count - 1 {
                viewModel.addMore()
            }
        }
        .onAppear {
            viewModel.onAppear()
        }
    }
}



//#Preview {
//    SwipeFeedView()
//}
