//
//  SunoNetworkManager.swift
//  Suno
//
//  Created by Martin Camacho on 3/14/24.
//

import Foundation
import ClerkSDK

struct PlaylistClip: Decodable {
    var clip: Clip
    var relativeIndex: Int
}

struct PlaylistResponse: Identifiable, Decodable {
    var id: UUID
    var playlistClips: [PlaylistClip]
}

class NetworkManager: ObservableObject {
    private var baseUrl: String = "https://api-staging.suno.ai"
    
    func fetchData(completion: @escaping ([Clip]) -> Void) {
        let url = URL(string: "\(baseUrl)/api/feed/")!
        var request = URLRequest(url: url)
        print("session", Clerk.shared.session)
        request.setValue(
            "Bearer dc30613777cf412593bd54cb9bba2de6",
            forHTTPHeaderField: "Authorization"
        )
        
        URLSession.shared.dataTask(with: request) { data, _, _ in
            if let data = data {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase
                
                let items = try? decoder.decode([Clip].self, from: data)
                DispatchQueue.main.async {
                    completion(items ?? [])
                }
            }
        }.resume()
    }
    
    func fetchData2() async throws -> [Clip] {
        let tokenResource = try await Clerk.shared.session?.getToken(Session.GetTokenOptions(template: "api"))
        guard let jwt = tokenResource?.jwt else {
            throw NSError(domain: "TokenError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to fetch token"])
        }
        
        let url = URL(string: "https://api-staging.suno.ai/api/feed/")!
        var request = URLRequest(url: url)
        request.setValue("Bearer \(jwt)", forHTTPHeaderField: "Authorization")
        
        let (data, _) = try await URLSession.shared.data(for: request)
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        let items = try decoder.decode([Clip].self, from: data)
        return items
    }
    
    func fetchTrending() async throws -> [Clip] {
        let tokenResource = try await Clerk.shared.session?.getToken(Session.GetTokenOptions(template: "api"))
        guard let jwt = tokenResource?.jwt else {
            throw NSError(domain: "TokenError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to fetch token"])
        }
        
        let url = URL(string: "https://api-staging.suno.ai/api/playlist/1190bf92-10dc-4ce5-968a-7a377f37f984/")!
        var request = URLRequest(url: url)
        request.setValue("Bearer \(jwt)", forHTTPHeaderField: "Authorization")
        
        let (data, _) = try await URLSession.shared.data(for: request)
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        let playlist = try decoder.decode(PlaylistResponse.self, from: data)
        return playlist.playlistClips.map { $0.clip }
    }
    
//    func runGenerateV2(text: String, completion: @escaping (Result<Data, Error>) -> Void) {
//        let url = URL(string: "https://api-staging.suno.ai/api/generate/v2/")!
//        var request = URLRequest(url: url)
//        request.httpMethod = "POST"
//        request.setValue("Bearer dc30613777cf412593bd54cb9bba2de6", forHTTPHeaderField: "Authorization")
//        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
//        
//        let requestBody = GenerateRequestBody(gptDescriptionPrompt: text, mv: "chirp-v3-alpha", prompt: "")
//        let encoder = JSONEncoder()
//        encoder.keyEncodingStrategy = .convertToSnakeCase
//        guard let jsonData = try? encoder.encode(requestBody) else {
//            completion(.failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid request body"])))
//            return
//        }
//        
//        request.httpBody = jsonData
//        
//        URLSession.shared.dataTask(with: request) { data, response, error in
//            if let error = error {
//                completion(.failure(error))
//                return
//            }
//            
//            guard let data = data else {
//                completion(.failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "No data received"])))
//                return
//            }
//            
//            completion(.success(data))
//        }.resume()
//    }
//    
    func runGenerate(text: String) async throws -> Data {
        let tokenResource = try await Clerk.shared.session?.getToken(Session.GetTokenOptions(template: "api"))
        guard let jwt = tokenResource?.jwt else {
            throw NSError(domain: "TokenError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to fetch token"])
        }
        
        let url = URL(string: "\(baseUrl)/api/generate/v2/")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("Bearer \(jwt)", forHTTPHeaderField: "Authorization")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        let requestBody = GenerateRequestBody(gptDescriptionPrompt: text, mv: "chirp-v3-engine-i", prompt: "")
        let encoder = JSONEncoder()
        encoder.keyEncodingStrategy = .convertToSnakeCase
        guard let jsonData = try? encoder.encode(requestBody) else {
            throw NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid request body"])
        }
        
        request.httpBody = jsonData
        
        let (data, response) = try await URLSession.shared.data(for: request)
        
        // Optionally, you can check the response status code here and throw an error if it's not in the 200-299 range
//        guard let httpResponse = response as? HTTPURLResponse, 200...299 contains httpResponse.statusCode else {
//            throw NSError(domain: "", code: (response as? HTTPURLResponse)?.statusCode ?? 0, userInfo: [NSLocalizedDescriptionKey: "Server error"])
//        }
        
        return data
    }
}
