//
// StoreAPI.swift
//
// Generated by openapi-generator
// https://openapi-generator.tech

import Foundation
import Combine
import OpenAPITransport


open class StoreAPI {
    private let transport: OpenAPITransport
    public var encoder: JSONEncoder = {
        let encoder = JSONEncoder()
        encoder.dateEncodingStrategy = .formatted(OpenISO8601DateFormatter())
        return encoder
    }()
    public var decoder: JSONDecoder = {
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .formatted(OpenISO8601DateFormatter())
        return decoder
    }()
    public var baseURL = URL(string: "http://petstore.swagger.io/v2")

    public init(_ transport: OpenAPITransport) {
        self.transport = transport
    }

    public enum DeleteOrderError: Error, CustomStringConvertible {
        // Invalid ID supplied
        case code400Error
        // Order not found
        case code404Error

        public var description: String {
            switch self {
            case .code400Error:
                return "DeleteOrderError: Invalid ID supplied"
            case .code404Error:
                return "DeleteOrderError: Order not found"
            }
        }
    }

    /// Delete purchase order by ID
    /// - DELETE /store/order/{orderId}
    /// - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
    /// - parameter orderId: (path) ID of the order that needs to be deleted 
    /// - returns: AnyPublisher<Void, Error> 
    open func deleteOrder(orderId: String) -> AnyPublisher<Void, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                var path = "/store/order/{orderId}"
                path = path.replacingOccurrences(of: "{orderId}", with: orderId)
                let url = baseURL.appendingPathComponent(path)
                let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
                guard let requestURL = components?.url else {
                    throw OpenAPITransportError.badURLError()
                }
                var request = URLRequest(url: requestURL)
                request.httpMethod = "DELETE"
                return request
            }.publisher
        }.flatMap { request -> AnyPublisher<Void, Error> in 
            return self.transport.send(request: request)
                .mapError { transportError -> Error in 
                    if transportError.statusCode == 400 {
                        return DeleteOrderError.code400Error
                    }
                    if transportError.statusCode == 404 {
                        return DeleteOrderError.code404Error
                    }
                    return transportError
                }
                .tryMap { response in
                    return ()
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }


    /// Returns pet inventories by status
    /// - GET /store/inventory
    /// - Returns a map of status codes to quantities
    /// - API Key:
    /// - type: apiKey api_key 
    /// - name: api_key
    /// - returns: AnyPublisher<[String: Int], Error> 
    open func getInventory() -> AnyPublisher<[String: Int], Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                let path = "/store/inventory"
                let url = baseURL.appendingPathComponent(path)
                let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
                guard let requestURL = components?.url else {
                    throw OpenAPITransportError.badURLError()
                }
                var request = URLRequest(url: requestURL)
                request.httpMethod = "GET"
                return request
            }.publisher
        }.flatMap { request -> AnyPublisher<[String: Int], Error> in 
            return self.transport.send(request: request)
                .tryMap { response in
                    try self.decoder.decode([String: Int].self, from: response.data)
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }

    public enum GetOrderByIdError: Error, CustomStringConvertible {
        // Invalid ID supplied
        case code400Error
        // Order not found
        case code404Error

        public var description: String {
            switch self {
            case .code400Error:
                return "GetOrderByIdError: Invalid ID supplied"
            case .code404Error:
                return "GetOrderByIdError: Order not found"
            }
        }
    }

    /// Find purchase order by ID
    /// - GET /store/order/{orderId}
    /// - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions
    /// - parameter orderId: (path) ID of pet that needs to be fetched 
    /// - returns: AnyPublisher<Order, Error> 
    open func getOrderById(orderId: Int64) -> AnyPublisher<Order, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                var path = "/store/order/{orderId}"
                path = path.replacingOccurrences(of: "{orderId}", with: "\(orderId)")
                let url = baseURL.appendingPathComponent(path)
                let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
                guard let requestURL = components?.url else {
                    throw OpenAPITransportError.badURLError()
                }
                var request = URLRequest(url: requestURL)
                request.httpMethod = "GET"
                return request
            }.publisher
        }.flatMap { request -> AnyPublisher<Order, Error> in 
            return self.transport.send(request: request)
                .mapError { transportError -> Error in 
                    if transportError.statusCode == 400 {
                        return GetOrderByIdError.code400Error
                    }
                    if transportError.statusCode == 404 {
                        return GetOrderByIdError.code404Error
                    }
                    return transportError
                }
                .tryMap { response in
                    try self.decoder.decode(Order.self, from: response.data)
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }

    public enum PlaceOrderError: Error, CustomStringConvertible {
        // Invalid Order
        case code400Error

        public var description: String {
            switch self {
            case .code400Error:
                return "PlaceOrderError: Invalid Order"
            }
        }
    }

    /// Place an order for a pet
    /// - POST /store/order
    /// - 
    /// - parameter order: (body) order placed for purchasing the pet 
    /// - returns: AnyPublisher<Order, Error> 
    open func placeOrder(order: Order) -> AnyPublisher<Order, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                let path = "/store/order"
                let url = baseURL.appendingPathComponent(path)
                let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
                guard let requestURL = components?.url else {
                    throw OpenAPITransportError.badURLError()
                }
                var request = URLRequest(url: requestURL)
                request.httpMethod = "POST"
                request.httpBody = try self.encoder.encode(order)
                request.setValue("application/json", forHTTPHeaderField: "Content-Type")
                return request
            }.publisher
        }.flatMap { request -> AnyPublisher<Order, Error> in 
            return self.transport.send(request: request)
                .mapError { transportError -> Error in 
                    if transportError.statusCode == 400 {
                        return PlaceOrderError.code400Error
                    }
                    return transportError
                }
                .tryMap { response in
                    try self.decoder.decode(Order.self, from: response.data)
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }
}
