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

import Foundation
import Combine
import OpenAPITransport


open class UserAPI {
    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
    }


    /// Create user
    /// - POST /user
    /// - This can only be done by the logged in user.
    /// - API Key:
    /// - type: apiKey api_key 
    /// - name: api_key
    /// - parameter user: (body) Created user object 
    /// - returns: AnyPublisher<Void, Error> 
    open func createUser(user: User) -> AnyPublisher<Void, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                let path = "/user"
                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(user)
                request.setValue("application/json", forHTTPHeaderField: "Content-Type")
                return request
            }.publisher
        }.flatMap { request -> AnyPublisher<Void, Error> in 
            return self.transport.send(request: request)
                .tryMap { response in
                    return ()
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }


    /// Creates list of users with given input array
    /// - POST /user/createWithArray
    /// - 
    /// - API Key:
    /// - type: apiKey api_key 
    /// - name: api_key
    /// - parameter user: (body) List of user object 
    /// - returns: AnyPublisher<Void, Error> 
    open func createUsersWithArrayInput(user: [User]) -> AnyPublisher<Void, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                let path = "/user/createWithArray"
                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(user)
                request.setValue("application/json", forHTTPHeaderField: "Content-Type")
                return request
            }.publisher
        }.flatMap { request -> AnyPublisher<Void, Error> in 
            return self.transport.send(request: request)
                .tryMap { response in
                    return ()
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }


    /// Creates list of users with given input array
    /// - POST /user/createWithList
    /// - 
    /// - API Key:
    /// - type: apiKey api_key 
    /// - name: api_key
    /// - parameter user: (body) List of user object 
    /// - returns: AnyPublisher<Void, Error> 
    open func createUsersWithListInput(user: [User]) -> AnyPublisher<Void, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                let path = "/user/createWithList"
                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(user)
                request.setValue("application/json", forHTTPHeaderField: "Content-Type")
                return request
            }.publisher
        }.flatMap { request -> AnyPublisher<Void, Error> in 
            return self.transport.send(request: request)
                .tryMap { response in
                    return ()
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }

    public enum DeleteUserError: Error, CustomStringConvertible {
        // Invalid username supplied
        case code400Error
        // User not found
        case code404Error

        public var description: String {
            switch self {
            case .code400Error:
                return "DeleteUserError: Invalid username supplied"
            case .code404Error:
                return "DeleteUserError: User not found"
            }
        }
    }

    /// Delete user
    /// - DELETE /user/{username}
    /// - This can only be done by the logged in user.
    /// - API Key:
    /// - type: apiKey api_key 
    /// - name: api_key
    /// - parameter username: (path) The name that needs to be deleted 
    /// - returns: AnyPublisher<Void, Error> 
    open func deleteUser(username: String) -> AnyPublisher<Void, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                var path = "/user/{username}"
                path = path.replacingOccurrences(of: "{username}", with: username)
                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 DeleteUserError.code400Error
                    }
                    if transportError.statusCode == 404 {
                        return DeleteUserError.code404Error
                    }
                    return transportError
                }
                .tryMap { response in
                    return ()
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }

    public enum GetUserByNameError: Error, CustomStringConvertible {
        // Invalid username supplied
        case code400Error
        // User not found
        case code404Error

        public var description: String {
            switch self {
            case .code400Error:
                return "GetUserByNameError: Invalid username supplied"
            case .code404Error:
                return "GetUserByNameError: User not found"
            }
        }
    }

    /// Get user by user name
    /// - GET /user/{username}
    /// - 
    /// - parameter username: (path) The name that needs to be fetched. Use user1 for testing. 
    /// - returns: AnyPublisher<User, Error> 
    open func getUserByName(username: String) -> AnyPublisher<User, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                var path = "/user/{username}"
                path = path.replacingOccurrences(of: "{username}", with: username)
                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<User, Error> in 
            return self.transport.send(request: request)
                .mapError { transportError -> Error in 
                    if transportError.statusCode == 400 {
                        return GetUserByNameError.code400Error
                    }
                    if transportError.statusCode == 404 {
                        return GetUserByNameError.code404Error
                    }
                    return transportError
                }
                .tryMap { response in
                    try self.decoder.decode(User.self, from: response.data)
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }

    public enum LoginUserError: Error, CustomStringConvertible {
        // Invalid username/password supplied
        case code400Error

        public var description: String {
            switch self {
            case .code400Error:
                return "LoginUserError: Invalid username/password supplied"
            }
        }
    }

    /// Logs user into the system
    /// - GET /user/login
    /// - 
    /// - responseHeaders: [Set-Cookie(String), X-Rate-Limit(Int), X-Expires-After(Date)]
    /// - parameter username: (query) The user name for login 
    /// - parameter password: (query) The password for login in clear text 
    /// - returns: AnyPublisher<String, Error> 
    open func loginUser(username: String, password: String) -> AnyPublisher<String, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                let path = "/user/login"
                let url = baseURL.appendingPathComponent(path)
                var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
                var queryItems: [URLQueryItem] = []
                queryItems.append(URLQueryItem(name: "username", value: username))
                queryItems.append(URLQueryItem(name: "password", value: password))
                components?.queryItems = queryItems
                guard let requestURL = components?.url else {
                    throw OpenAPITransportError.badURLError()
                }
                var request = URLRequest(url: requestURL)
                request.httpMethod = "GET"
                return request
            }.publisher
        }.flatMap { request -> AnyPublisher<String, Error> in 
            return self.transport.send(request: request)
                .mapError { transportError -> Error in 
                    if transportError.statusCode == 400 {
                        return LoginUserError.code400Error
                    }
                    return transportError
                }
                .tryMap { response in
                    try self.decoder.decode(String.self, from: response.data)
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }


    /// Logs out current logged in user session
    /// - GET /user/logout
    /// - 
    /// - API Key:
    /// - type: apiKey api_key 
    /// - name: api_key
    /// - returns: AnyPublisher<Void, Error> 
    open func logoutUser() -> AnyPublisher<Void, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                let path = "/user/logout"
                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<Void, Error> in 
            return self.transport.send(request: request)
                .tryMap { response in
                    return ()
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }

    public enum UpdateUserError: Error, CustomStringConvertible {
        // Invalid user supplied
        case code400Error
        // User not found
        case code404Error

        public var description: String {
            switch self {
            case .code400Error:
                return "UpdateUserError: Invalid user supplied"
            case .code404Error:
                return "UpdateUserError: User not found"
            }
        }
    }

    /// Updated user
    /// - PUT /user/{username}
    /// - This can only be done by the logged in user.
    /// - API Key:
    /// - type: apiKey api_key 
    /// - name: api_key
    /// - parameter username: (path) name that need to be deleted 
    /// - parameter user: (body) Updated user object 
    /// - returns: AnyPublisher<Void, Error> 
    open func updateUser(username: String, user: User) -> AnyPublisher<Void, Error> {
        Deferred {
            Result<URLRequest, Error> {
                guard let baseURL = self.transport.baseURL ?? self.baseURL else {
                    throw OpenAPITransportError.badURLError()
                }
                var path = "/user/{username}"
                path = path.replacingOccurrences(of: "{username}", with: username)
                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 = "PUT"
                request.httpBody = try self.encoder.encode(user)
                request.setValue("application/json", forHTTPHeaderField: "Content-Type")
                return request
            }.publisher
        }.flatMap { request -> AnyPublisher<Void, Error> in 
            return self.transport.send(request: request)
                .mapError { transportError -> Error in 
                    if transportError.statusCode == 400 {
                        return UpdateUserError.code400Error
                    }
                    if transportError.statusCode == 404 {
                        return UpdateUserError.code404Error
                    }
                    return transportError
                }
                .tryMap { response in
                    return ()
                }
                .eraseToAnyPublisher()
        }.eraseToAnyPublisher()
    }
}
