import PixelPaySDK

@objc(ReactNativePlugin)
class ReactNativePlugin: NSObject {

	internal func fromJson<T>(type: T.Type, json: String) throws -> T where T : Decodable {
		let decoder = JSONDecoder();

		return try decoder.decode(type, from: Data(json.utf8))
	}

	internal func getTransactionService(settings: String) throws -> Transaction {
		return Transaction(settings: try self.fromJson(type: Settings.self, json: settings));
	}

	internal func getTokenizationService(settings: String) throws -> Tokenization {
		return Tokenization(settings: try self.fromJson(type: Settings.self, json: settings));
	}

	internal func parseSuccess(_ resolve:RCTPromiseResolveBlock, response: Response) {
		resolve([
			"status": String(response.getStatus() ?? 500),
			"response": response.toJson()
		])
	}

	internal func parseError(_ reject:RCTPromiseRejectBlock, error: Error) {
		reject("pixelpay-sdk-exception", error.localizedDescription, nil)
	}

	@objc(transactionDoSale:withRequest:withResolver:withRejecter:)
	func transactionDoSale(settings: String, request: String, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		do {
			try self.getTransactionService(settings: settings)
				.doSale(transaction: self.fromJson(type: SaleTransaction.self, json: request)) { response in
					self.parseSuccess(resolve, response: response)
				}
		} catch {
			self.parseError(reject, error: error)
		}
	}

	@objc(transactionDoAuth:withRequest:withResolver:withRejecter:)
	func transactionDoAuth(settings: String, request: String, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		do {
			try self.getTransactionService(settings: settings)
				.doAuth(transaction: self.fromJson(type: AuthTransaction.self, json: request)) { response in
					self.parseSuccess(resolve, response: response)
				}
		} catch {
			self.parseError(reject, error: error)
		}
	}

	@objc(transactionDoCapture:withRequest:withResolver:withRejecter:)
	func transactionDoCapture(settings: String, request: String, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		do {
			try self.getTransactionService(settings: settings)
				.doCapture(transaction: self.fromJson(type: CaptureTransaction.self, json: request)) { response in
					self.parseSuccess(resolve, response: response)
				}
		} catch {
			self.parseError(reject, error: error)
		}
	}

	@objc(transactionDoVoid:withRequest:withResolver:withRejecter:)
	func transactionDoVoid(settings: String, request: String, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		do {
			try self.getTransactionService(settings: settings)
				.doVoid(transaction: self.fromJson(type: VoidTransaction.self, json: request)) { response in
					self.parseSuccess(resolve, response: response)
				}
		} catch {
			self.parseError(reject, error: error)
		}
	}

	@objc(transactionGetStatus:withRequest:withResolver:withRejecter:)
	func transactionGetStatus(settings: String, request: String, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		do {
			try self.getTransactionService(settings: settings)
				.getStatus(transaction: self.fromJson(type: StatusTransaction.self, json: request)) { response in
					self.parseSuccess(resolve, response: response)
				}
		} catch {
			self.parseError(reject, error: error)
		}
	}

	@objc(tokenizationVaultCard:withRequest:withResolver:withRejecter:)
	func tokenizationVaultCard(settings: String, request: String, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		do {
			try self.getTokenizationService(settings: settings)
				.vaultCard(card: self.fromJson(type: CardTokenization.self, json: request)) { response in
					self.parseSuccess(resolve, response: response)
				}
		} catch {
			self.parseError(reject, error: error)
		}
	}

	@objc(tokenizationUpdateCard:withToken:withRequest:withResolver:withRejecter:)
	func tokenizationUpdateCard(settings: String, token: String, request: String, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		do {
			try self.getTokenizationService(settings: settings)
				.updateCard(token: token, card: self.fromJson(type: CardTokenization.self, json: request)) { response in
					self.parseSuccess(resolve, response: response)
					}
		} catch {
			self.parseError(reject, error: error)
		}
	}

	@objc(tokenizationShowCard:withToken:withResolver:withRejecter:)
	func tokenizationShowCard(settings: String, token: String, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		do {
			try self.getTokenizationService(settings: settings)
				.showCard(token: token) { response in
					self.parseSuccess(resolve, response: response)
				}
		} catch {
			self.parseError(reject, error: error)
		}
	}

	@objc(tokenizationShowCards:withTokens:withResolver:withRejecter:)
	func tokenizationShowCards(settings: String, tokens: String, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		do {
			try self.getTokenizationService(settings: settings)
				.showCards(tokens: tokens.components(separatedBy: "|")) { response in
					self.parseSuccess(resolve, response: response)
				}
		} catch {
			self.parseError(reject, error: error)
		}
	}

	@objc(tokenizationDeleteCard:withToken:withResolver:withRejecter:)
	func tokenizationDeleteCard(settings: String, token: String, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		do {
			try self.getTokenizationService(settings: settings)
				.deleteCard(token: token) { response in
					self.parseSuccess(resolve, response: response)
				}
		} catch {
			self.parseError(reject, error: error)
		}
	}

	@objc(multiply:withB:withResolver:withRejecter:)
	func multiply(a: Float, b: Float, resolve:@escaping RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
		resolve(a*b)
	}
}
