//
//  Network.swift
//  Werkout_ios
//
//  Created by Trey Tartt on 6/19/23.
//

import Foundation

enum FetchableError: Error {
    case apiError(Error)
    case noData
    case decodeError(Error)
    case endOfFileError
    case noPostData
    case statusError(Int)
}

protocol Fetchable {
    associatedtype Response: Codable
    
    var baseURL: String { get }
    var endPoint: String { get }
    func fetch(completion: @escaping (Result<Response, FetchableError>) -> Void)
}

protocol Postable: Fetchable {
    var postableData: [String: Any]? { get }
}

extension Fetchable {
    var baseURL: String {
        "http://127.0.0.1:8000/"
    }
    
    func fetch(completion: @escaping (Result<Response, FetchableError>) -> Void) {
        let url = URL(string: baseURL+endPoint)!
        
        let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
            if let error = error {
                completion(.failure(.apiError(error)))
                return
            }
            guard let data = data else {
                completion(.failure(.noData))
                return
            }
            
            do {
                let model = try JSONDecoder().decode(Response.self, from: data)
                completion(.success(model))
                return
            } catch {
                completion(.failure(.decodeError(error)))
                return
            }
        })
        
        task.resume()
    }
}

extension Postable {
   func fetch(completion: @escaping (Result<Response, FetchableError>) -> Void) {
        guard let postableData = postableData else {
            completion(.failure(.noPostData))
            return
        }
        
        let url = URL(string: baseURL+endPoint)!
        
       let postData = try! JSONSerialization.data(withJSONObject:postableData)
       
       var request = URLRequest(url: url,timeoutInterval: Double.infinity)
       request.addValue("Token fd59cbf6f5db98726e896cdb6b095ecb9c43a592", forHTTPHeaderField: "Authorization")
       request.addValue("application/json", forHTTPHeaderField: "Content-Type")
       
       request.httpMethod = "POST"
       request.httpBody = postData
        
        let task = URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in
            if let error = error {
                completion(.failure(.apiError(error)))
                return
            }
            
            if let httpRespone = response as? HTTPURLResponse {
                if httpRespone.statusCode != 201 {
                    completion(.failure(.statusError(httpRespone.statusCode)))
                    return
                }
            }
            
            guard let data = data else {
                completion(.failure(.noData))
                return
            }
            
            do {
                let model = try JSONDecoder().decode(Response.self, from: data)
                completion(.success(model))
                return
            } catch {
                completion(.failure(.decodeError(error)))
                return
            }
        })
        
        task.resume()
    }
}
