<?php
use Give\Framework\PaymentGateways\Commands\RedirectOffsite;
use Give\Framework\PaymentGateways\Exceptions\PaymentGatewayException;
use Give\Donations\Models\Donation;
use Webimpian\BayarcashSdk\Bayarcash as BayarcashSdk;
use BayarcashGiveWP\Webimpian\BayarcashSdk\Exceptions\ValidationException;
use BayarCash\GiveWP\ErrorMonitor;

trait BayarcashPaymentTrait {
	private static bool $script_loaded = false;
	private BayarcashSdk $bayarcashSdk;

	public function getLegacyFormFieldMarkup($formId, $args): string {
		return "<div class=''>
            <p>You will be redirected to " . $this->getName() . "</p>
        </div>";
	}

	public function enqueueScript(int $formId) {
		BayarcashScriptLoader::enqueueScript();
	}


	public function createPayment(Donation $donation, $gatewayData): RedirectOffsite {
		$form_id = $donation->formId;
		$tokens = $this->getEndpointTokens($form_id);
		$gatewayId = $gatewayData['gatewayId'] ?? $donation->gatewayId ?? null;

		if (empty($gatewayId)) {
			throw new PaymentGatewayException(__('Gateway ID is required.', 'bayarcash-for-givewp'));
		}

		try {
			$payment_mode = $this->mapGatewayIdToPaymentMode($gatewayId);
		} catch (\Exception $e) {
			throw new PaymentGatewayException(__('Invalid payment gateway selected.', 'bayarcash-for-givewp'));
		}

		if (!isset($tokens->$payment_mode)) {
			throw new PaymentGatewayException(__('Invalid payment mode selected.', 'bayarcash-for-givewp'));
		}

		$channel_tokens = $tokens->$payment_mode;
		$this->bayarcashSdk = new BayarcashSdk($channel_tokens['portal_token']);

		if (give_is_test_mode()) {
			$this->bayarcashSdk->useSandbox();
		}

		$args = [
			'portal_key' => $channel_tokens['portal_key'],
			'order_number' => $donation->id,
			'amount' => $donation->amount->getAmount() / 100,
			'payer_name' => trim($donation->firstName . ' ' . $donation->lastName),
			'payer_email' => $donation->email,
			'payer_telephone_number' => $gatewayData['phone'] ?? '',
			'return_url' => site_url('/give-api/bayarcash_gateway/?bc-givewp-return=' . $this->createReturnToken($donation->id)),
			'payment_channel' => $channel_tokens['payment_channel'],
		];

		$args['checksum'] = $this->bayarcashSdk->createPaymentIntenChecksumValue($channel_tokens['secret_key'], $args);

		try {
			$response = $this->bayarcashSdk->createPaymentIntent($args);

			if (empty($response->url)) {
				throw new PaymentGatewayException(__('Failed to create payment intent with Bayarcash SDK', 'bayarcash-for-givewp'));
			}

			if (give_is_test_mode()) {
				give_insert_payment_note($donation->id, __('This is test environment where payment status is simulated.', 'bayarcash-for-givewp'));
			}
			give_insert_payment_note($donation->id, sprintf(__('URL: %s', 'bayarcash-for-givewp'), $response->url));

			return new RedirectOffsite($response->url);

		} catch (ValidationException $e) {
			give_insert_payment_note($donation->id, 'Validation Error: ' . $e->getMessage());

			// Extract validation errors
			$validation_errors = $e->errors();
			$error_details = print_r($validation_errors, true);

			// Get first error message for display
			$display_message = $e->getMessage();
			if (!empty($validation_errors['errors'])) {
				$first_error = reset($validation_errors['errors']);
				if (is_array($first_error)) {
					$display_message = reset($first_error);
				}
			} elseif (isset($validation_errors['message'])) {
				$display_message = $validation_errors['message'];
			}

			// Report error to monitoring service (use same credentials as payment intent)
			ErrorMonitor::report([
				'portal_key' => $channel_tokens['portal_key'],
				'secret_key' => $channel_tokens['secret_key'],
				'bearer_token' => $channel_tokens['portal_token'],
				'error_message' => 'Validation error: ' . $e->getMessage(),
				'error_details' => $error_details,
				'payment_id' => $donation->id,
				'payment_channel' => $this->getName(),
				'amount' => $donation->amount->getAmount() / 100,
				'request_data' => $args,
				'response_data' => $validation_errors,
				'test_mode' => give_is_test_mode(),
			]);

			throw new PaymentGatewayException(esc_html($display_message));

		} catch (\Exception $e) {
			give_insert_payment_note($donation->id, 'Payment Error: ' . $e->getMessage());

			$error_message = $e->getMessage();
			$display_message = $error_message;

			// Try to decode error message as JSON to get response data
			$response_data = null;
			$json_error = json_decode($error_message, true);
			if ($json_error) {
				$response_data = $json_error;
				if (isset($json_error['error'])) {
					$display_message = $json_error['error'];
				}
			}

			// Report error to monitoring service (use same credentials as payment intent)
			ErrorMonitor::report([
				'portal_key' => $channel_tokens['portal_key'],
				'secret_key' => $channel_tokens['secret_key'],
				'bearer_token' => $channel_tokens['portal_token'],
				'error_message' => 'Payment intent error: ' . $e->getMessage(),
				'error_details' => $e->getTraceAsString(),
				'payment_id' => $donation->id,
				'payment_channel' => $this->getName(),
				'amount' => $donation->amount->getAmount() / 100,
				'request_data' => $args,
				'response_data' => $response_data,
				'test_mode' => give_is_test_mode(),
			]);

			throw new PaymentGatewayException(esc_html($display_message));
		}
	}

	private function getEndpointTokens($form_id): object {
		$channels = [
			'bayarcash' => ['key' => 'bayarcash', 'payment_channel' => 1],
			'bayarcash_duitnow' => ['key' => 'bc-duitnow', 'payment_channel' => 5],
			'bayarcash_linecredit' => ['key' => 'bc-linecredit', 'payment_channel' => 4],
			'bayarcash_duitnowqr' => ['key' => 'bc-duitnowqr', 'payment_channel' => 6],
			// 'bayarcash_duitnowshopee' => ['key' => 'bc-duitnowshopee', 'payment_channel' => 7], // Temporarily disabled
			'bayarcash_duitnowboost' => ['key' => 'bc-duitnowboost', 'payment_channel' => 8],
			'bayarcash_duitnowqris' => ['key' => 'bc-duitnowqris', 'payment_channel' => 9],
			'bayarcash_duitnowqriswallet' => ['key' => 'bc-duitnowqriswallet', 'payment_channel' => 10],
			'bayarcash_nets' => ['key' => 'bc-nets', 'payment_channel' => 11],
			'bayarcash_alipay' => ['key' => 'bc-alipay', 'payment_channel' => 13],
			'bayarcash_wechatpay' => ['key' => 'bc-wechatpay', 'payment_channel' => 14],
			'bayarcash_promptpay' => ['key' => 'bc-promptpay', 'payment_channel' => 15],
		];

		$tokens = [];
		foreach ($channels as $payment_mode => $channel) {
			$setting_key = $channel['key'];
			$customize_donations = give_get_meta($form_id, "{$setting_key}_givewp_customize_donations", true) === 'enabled';

			if ($customize_donations) {
				$portal_token = give_get_meta($form_id, "{$setting_key}_portal_token", true);
				$portal_key = give_get_meta($form_id, "{$setting_key}_portal_key", true);
				$secret_key = give_get_meta($form_id, "{$setting_key}_secret_key", true);
			} else {
				$portal_token = give_get_option("{$setting_key}_portal_token");
				$portal_key = give_get_option("{$setting_key}_portal_key");
				$secret_key = give_get_option("{$setting_key}_secret_key");
			}

			$tokens[$payment_mode] = [
				'portal_token' => $portal_token,
				'portal_key' => $portal_key,
				'secret_key' => $secret_key,
				'payment_channel' => $channel['payment_channel'],
			];
		}

		$endpoint = give_is_test_mode() ? 'https://sandbox.bayar.cash/api' : 'https://bayar.cash/api';

		return (object) array_merge(
			$tokens,
			[
				'directdebit_request_url' => $endpoint.'/mandates/enrollment/confirmation',
				'directdebit_cancel_url'  => $endpoint.'/mandates/termination',
			]
		);
	}

	/**
	 * @throws Exception
	 */
	private function mapGatewayIdToPaymentMode(string $gatewayId): string {
		$gatewayMap = [
			'bayarcash_block' => 'bayarcash',
			'bayarcash_duitnow_block' => 'bayarcash_duitnow',
			'bayarcash_linecredit_block' => 'bayarcash_linecredit',
			'bayarcash_duitnowqr_block' => 'bayarcash_duitnowqr',
			// 'bayarcash_duitnowshopee_block' => 'bayarcash_duitnowshopee', // Temporarily disabled
			'bayarcash_duitnowboost_block' => 'bayarcash_duitnowboost',
			'bayarcash_duitnowqris_block' => 'bayarcash_duitnowqris',
			'bayarcash_duitnowqriswallet_block' => 'bayarcash_duitnowqriswallet',
			'bayarcash_nets_block' => 'bayarcash_nets',
			'bayarcash_alipay_block' => 'bayarcash_alipay',
			'bayarcash_wechatpay_block' => 'bayarcash_wechatpay',
			'bayarcash_promptpay_block' => 'bayarcash_promptpay'
		];

		if (!isset($gatewayMap[$gatewayId])) {
			throw new \Exception(sprintf('Unsupported gateway ID: %s', $gatewayId));
		}

		return $gatewayMap[$gatewayId];
	}

	private function createReturnToken(string $payment_id): string {
		return wp_create_nonce('bc-givewp-return-' . $payment_id);
	}
}

class BayarcashScriptLoader {
	private static bool $script_loaded = false;

	public static function enqueueScript() {
		if (self::$script_loaded) {
			return;
		}

		self::$script_loaded = true;

		wp_enqueue_script(
			'bayarcash-gateway',  // Use a common handle for all gateways
			plugin_dir_url(__FILE__) . '../js/bayarcash-gateway.js',
			['react', 'wp-element'],
			'1.0.0',
			true
		);
	}
}