import Foundation

@MainActor
class NetworkService: ObservableObject {
    nonisolated static let shared = NetworkService()
    
    private let baseURL = "http://127.0.0.1:9001" // Change this to your server URL
    
    @Published var isUploading = false
    @Published var uploadProgress: Double = 0.0
    
    nonisolated private init() {}
    
    func uploadAudioFile(at url: URL) async -> Result<UploadResponse, NetworkError> {
        guard let data = try? Data(contentsOf: url) else {
            return .failure(.fileReadError)
        }
        
        return await uploadAudioData(data, filename: url.lastPathComponent)
    }
    
    func uploadAudioData(_ data: Data, filename: String) async -> Result<UploadResponse, NetworkError> {
        isUploading = true
        uploadProgress = 0.0
        
        let url = URL(string: "\(baseURL)/upload-audio")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        
        let boundary = UUID().uuidString
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
        
        let body = createMultipartBody(data: data, filename: filename, boundary: boundary)
        request.httpBody = body
        
        do {
            let (responseData, response) = try await URLSession.shared.data(for: request)
            
            isUploading = false
            uploadProgress = 1.0
            
            guard let httpResponse = response as? HTTPURLResponse else {
                return .failure(.invalidResponse)
            }
            
            if httpResponse.statusCode == 200 {
                do {
                    let uploadResponse = try JSONDecoder().decode(UploadResponse.self, from: responseData)
                    return .success(uploadResponse)
                } catch {
                    return .failure(.decodingError)
                }
            } else {
                if let errorData = try? JSONDecoder().decode(ErrorResponse.self, from: responseData) {
                    return .failure(.serverError(errorData.message))
                } else {
                    return .failure(.httpError(httpResponse.statusCode))
                }
            }
        } catch {
            isUploading = false
            return .failure(.networkError(error))
        }
    }
    
    private func createMultipartBody(data: Data, filename: String, boundary: String) -> Data {
        var body = Data()
        
        // Add file data
        body.append("--\(boundary)\r\n".data(using: .utf8)!)
        body.append("Content-Disposition: form-data; name=\"audio\"; filename=\"\(filename)\"\r\n".data(using: .utf8)!)
        body.append("Content-Type: audio/mp4\r\n\r\n".data(using: .utf8)!)
        body.append(data)
        body.append("\r\n".data(using: .utf8)!)
        
        // End boundary
        body.append("--\(boundary)--\r\n".data(using: .utf8)!)
        
        return body
    }
    
    func parseAudioWithAI(audioURL: String, categories: [CategoryInfo]) async -> Result<ParseAudioResponse, NetworkError> {
        let url = URL(string: "\(baseURL)/parse-audio")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        let requestBody = ParseAudioRequest(
            audio_url: audioURL,
            categories: categories
        )
        
        do {
            let jsonData = try JSONEncoder().encode(requestBody)
            request.httpBody = jsonData
            
            let (responseData, response) = try await URLSession.shared.data(for: request)
            
            guard let httpResponse = response as? HTTPURLResponse else {
                return .failure(.invalidResponse)
            }
            
            if httpResponse.statusCode == 200 {
                do {
                    let parseResponse = try JSONDecoder().decode(ParseAudioResponse.self, from: responseData)
                    return .success(parseResponse)
                } catch {
                    return .failure(.decodingError)
                }
            } else {
                if let errorData = try? JSONDecoder().decode(ErrorResponse.self, from: responseData) {
                    return .failure(.serverError(errorData.message))
                } else {
                    return .failure(.httpError(httpResponse.statusCode))
                }
            }
        } catch {
            return .failure(.networkError(error))
        }
    }
}

// MARK: - Response Models
struct UploadResponse: Codable {
    let status: String
    let message: String
    let filename: String
    let url: String
}

struct ParseAudioRequest: Codable {
    let audio_url: String
    let categories: [CategoryInfo]
}

struct CategoryInfo: Codable {
    let name: String
    let iconName: String
}

struct ParseAudioResponse: Codable {
    let status: String
    let message: String
    let expenses: [ExpenseInfo]
    let raw_response: String?
}

struct ExpenseInfo: Codable {
    let amount: Double
    let title: String
    let category: String
}

struct ErrorResponse: Codable {
    let status: String
    let message: String
}

// MARK: - Network Errors
enum NetworkError: Error, LocalizedError {
    case fileReadError
    case invalidResponse
    case decodingError
    case serverError(String)
    case httpError(Int)
    case networkError(Error)
    
    var errorDescription: String? {
        switch self {
        case .fileReadError:
            return "无法读取音频文件"
        case .invalidResponse:
            return "服务器响应无效"
        case .decodingError:
            return "响应数据解析失败"
        case .serverError(let message):
            return "服务器错误: \(message)"
        case .httpError(let code):
            return "HTTP错误: \(code)"
        case .networkError(let error):
            return "网络错误: \(error.localizedDescription)"
        }
    }
} 