//
//  APICallsView.swift
//  PadelClub
//
//  Created by Laurent Morvillier on 27/05/2024.
//

import SwiftUI
import LeStorage

struct APICallsListView: View {
    
    @State var descriptors: [CollectionDescriptor] = []
    
    var body: some View {
        
        List {
            ForEach(self.descriptors) { descriptor in
                
                NavigationLink {
                    if let syncedType = descriptor.type as? any SyncedStorable.Type {
                        APICallsView(name: descriptor.name, type: syncedType)
                    }
                } label: {
                    LabeledContent(descriptor.name, value: descriptor.count.string)
                }

            }
        }.onAppear {
            self.load()
        }
    }
    
    func load() {
        Task {
            self.descriptors = await StoreCenter.main.apiCollectionDescriptors().map {
                CollectionDescriptor(name: $0.0, type: $0.1)
            }.sorted(by: \.name, order: .ascending)

            for descriptor in self.descriptors {
                if let type = descriptor.type as? any SyncedStorable.Type {
                    await self.loadCount(type, descriptor)
                }
            }
        }
    }
    
    func loadCount<T: SyncedStorable>(_ type: T.Type, _ descriptor: CollectionDescriptor) async {
        let calls = await StoreCenter.main.apiCalls(type: type)
        descriptor.count = calls.count
//        Logger.log("\(descriptor.name), count = \(calls.count)")
    }
    
}

@Observable
class CollectionDescriptor: Identifiable, Hashable {
    
    var id: UUID = UUID()
    var name: String
    var type: any Storable.Type
    var count: Int = 0
    
    init(name: String, type: any Storable.Type) {
        self.name = name
        self.type = type
    }
    
    static func == (lhs: CollectionDescriptor, rhs: CollectionDescriptor) -> Bool {
        return lhs.id == rhs.id
    }
    func hash(into hasher: inout Hasher) {
        hasher.combine(self.id)
    }

}

struct APICallsView: View {
    
    var name: String
    var type: any SyncedStorable.Type
    
//    @State var text: String = ""
    @State var apiCalls: [any SomeCall] = []
    
    var body: some View {
        List {
            Section(header:
                Text("\(apiCalls.count) API calls")
                    .font(.headline)
                    .foregroundColor(.primary)
            ) {
                ForEach(self.apiCalls, id: \.id) { apiCall in
                    NavigationLink {
                        APICallView(apiCall: apiCall, type: self.type)
                    } label: {
                        LabeledContent(apiCall.method.rawValue, value: apiCall.attemptsCount.string)
                    }
                }
            }
        }.navigationTitle(self.name)
        .onAppear {
            self._load()
        }
    }
    
    @MainActor
    fileprivate func _load() {
        Task {
            await self.load(self.type)
//            self.text = await StoreCenter.main.apiCallsFileContent(resourceName: self.name)
        }
    }
    
    func load<T: SyncedStorable>(_ type: T.Type) async {
        let calls: [ApiCall<T>] = await StoreCenter.main.apiCalls(type: type)
        self.apiCalls = calls
    }
    
}

struct APICallView: View {
    
    var apiCall: any SomeCall
    var type: any SyncedStorable.Type
    @State private var errorMessage: String? = nil
    @State private var isLoading: Bool = false
    @State private var showSuccessPopover: Bool = false
    
    var body: some View {
        Form {
            Section {
                LabeledContent("Method", value: apiCall.method.rawValue)
                LabeledContent("Data id", value: apiCall.stringId)
                LabeledContent("Attempts", value: apiCall.attemptsCount.string)
            }
            
            Section {
                if isLoading {
                    ProgressView()
                        .padding()
                } else {
                    
                    Button("Execute") {
                        self.execute()
                        // Clear previous error when attempting again
                        errorMessage = nil
                    }
                    .disabled(isLoading)
                }
                if let errorMessage = errorMessage {
                    LabeledContent("Error", value: errorMessage)
                    //                VStack(alignment: .leading) {
                    //                    Text("Error:")
                    //                        .fontWeight(.bold)
                    //                        .foregroundColor(.red)
                    //                    Text(errorMessage)
                    //                        .foregroundColor(.red)
                    //                }
                }
                if showSuccessPopover {
                    VStack {
                        Image(systemName: "checkmark.circle.fill")
                            .foregroundColor(.green)
                            .font(.title)
                        Text("Success")
                            .foregroundColor(.green)
                    }
                    .padding()
                    .background(
                        RoundedRectangle(cornerRadius: 8)
                            .fill(Color.white)
                            .shadow(radius: 2)
                    )
                    .transition(.scale.combined(with: .opacity))
                }

            }
            Section {
                Text(apiCall.dataContent ?? "none").monospaced().font(.caption)
            }
            
        }
        .animation(.easeInOut, value: showSuccessPopover)
        .navigationTitle(String(describing: self.type))
    }
    
    func execute() {
        self.execute(type: self.type)
    }
    
    func execute<T: SyncedStorable>(type: T.Type) {
        if let call = self.apiCall as? ApiCall<T> {
            Task {
                await MainActor.run {
                    isLoading = true
                }
                
                do {
                    let results = try await StoreCenter.main.execute(apiCalls: [call])
                    
                    await MainActor.run {
                        isLoading = false
                        if let result = results.first {
                            errorMessage = result.message
                            showSuccessPopover = (200..<300).contains(result.status)
                        } else {
                            errorMessage = "no results"
                        }
                    }
                    
                    // Update UI on the main thread
//                    await MainActor.run {
//                        errorMessage = nil
//                        isLoading = false
//                        
//                        // Show success popover
//                        showSuccessPopover = true
//                    }
                } catch {
                    // Update UI on the main thread
                    await MainActor.run {
                        errorMessage = error.localizedDescription
                        isLoading = false
                    }
                }
            }
        }
    }
}

//#Preview {
//    APICallsListView()
//}
