<?php
/**
 * MachForm
 * 
 * © 2007–2025 Appnitro Software. All rights reserved.
 * 
 * This source code is proprietary and may not be copied, modified,
 * or distributed in any form without express written permission from Appnitro Software.
 * 
 * License information: https://www.machform.com/license-agreement/
 */

	require('config.php');
	require('lib/db-session-handler.php');

	require('includes/init-form.php');
	
	require('includes/db-core.php');
	require('includes/helper-functions.php');
	require('includes/filter-functions.php');
	require('includes/post-functions.php');
	require('lib/stripe/init.php');

	$form_id 			= (int) trim($_POST['form_id'] ?? '0');
	$payment_record_id 	= (int) trim($_POST['record_id'] ?? '0');

	
	//make sure the user is having a valid session to access this form
	if(empty($form_id) || empty($payment_record_id) || empty($_SESSION['mf_form_payment_access'][$form_id])){
		echo json_encode([
			'status' => 'error',
			'message' => 'Error. Your session has expired. Please start the form again.'
		]);

		exit;
	}

	//the maximum number of allowed PaymentIntent generations within a session
	//this includes the initial PaymentIntent and any retries
	$max_failed_attempts = 5; //default is 5 attempts

	//if the user having too many attempts, exceeding the limit, invalidate the session
	if(isset($_SESSION['mf_payment_failed_attempts_counter'][$form_id])){
		$_SESSION['mf_payment_failed_attempts_counter'][$form_id]++;

		if($_SESSION['mf_payment_failed_attempts_counter'][$form_id] >= $max_failed_attempts){
			
			//invalidate current session
			$_SESSION['mf_payment_record_id'][$form_id] = 0;
			$_SESSION['mf_form_payment_access'][$form_id]  = false;
			$_SESSION['mf_form_completed'][$form_id] = false;
			$_SESSION['mf_payment_failed_attempts_counter'][$form_id] = 0;

			unset($_SESSION['mf_payment_record_id'][$form_id]);
			unset($_SESSION['mf_form_payment_access'][$form_id]);
			unset($_SESSION['mf_form_completed'][$form_id]);
			unset($_SESSION['mf_payment_failed_attempts_counter'][$form_id]);

			echo json_encode([
				'status' => 'error',
				'message' => 'Error. You have too many failed attempts. Please start the form again.'
			]);
			
			exit;
		}
	}else{
		if(isset($_SESSION['mf_form_payment_access'][$form_id]) && $_SESSION['mf_form_payment_access'][$form_id] == true){
			$_SESSION['mf_payment_failed_attempts_counter'][$form_id] = 0;
		}
	}

	$dbh = mf_connect_db();
	$mf_settings = mf_get_settings($dbh);
	
	//get form properties data
	$query 	= "select 
					form_name,
					form_review,
					form_page_total,
					payment_enable_merchant,
					payment_merchant_type,
					payment_currency,
					payment_price_type,
					payment_price_name,
					payment_price_amount,
					payment_ask_billing,
					payment_ask_shipping,
					payment_stripe_live_secret_key,
					payment_stripe_test_secret_key,
					payment_stripe_live_webhook_id,
					payment_stripe_test_webhook_id,
					payment_stripe_enable_test_mode,
					payment_stripe_enable_receipt,
					payment_stripe_receipt_element_id,
					payment_stripe_setup_future_usage,
					payment_enable_recurring,
					payment_recurring_cycle,
					payment_recurring_unit,
					payment_enable_trial,
					payment_trial_period,
					payment_trial_unit,
					payment_trial_amount,
					payment_enable_setupfee,
					payment_setupfee_amount,
					payment_delay_notifications,
					payment_enable_tax,
					payment_tax_rate,
					payment_enable_discount,
					payment_discount_type,
					payment_discount_amount,
					payment_discount_element_id 
				from 
				    ".MF_TABLE_PREFIX."forms 
			   where 
				    form_id=? and form_active=1";
	$params = array($form_id);
		
	$sth = mf_do_query($query,$params,$dbh);
	$row = mf_do_fetch_result($sth);
	
	if(!empty($row)){	
		$form_review  	 = (int) $row['form_review'];
		$form_page_total = (int) $row['form_page_total'];
			
		$payment_enable_merchant 	 = (int) $row['payment_enable_merchant'];

		$payment_enable_tax 		 = (int) $row['payment_enable_tax'];
		$payment_tax_rate 			 = (float) $row['payment_tax_rate'];

		$payment_currency 	   		 = strtolower($row['payment_currency']);
		$payment_price_type 	     = $row['payment_price_type'];
		$payment_price_amount    	 = $row['payment_price_amount'];
		$payment_ask_billing 	 	 = (int) $row['payment_ask_billing'];
		$payment_ask_shipping 	 	 = (int) $row['payment_ask_shipping'];
		$payment_merchant_type		 = $row['payment_merchant_type'];
		
		$payment_stripe_enable_test_mode 	= (int) $row['payment_stripe_enable_test_mode'];
		$payment_stripe_live_secret_key	 	= trim($row['payment_stripe_live_secret_key']);
		$payment_stripe_test_secret_key	 	= trim($row['payment_stripe_test_secret_key']);
		$payment_stripe_live_webhook_id	 	= $row['payment_stripe_live_webhook_id'];
		$payment_stripe_test_webhook_id	 	= $row['payment_stripe_test_webhook_id'];
		$payment_stripe_enable_receipt  	= (int) $row['payment_stripe_enable_receipt'];
		$payment_stripe_receipt_element_id  = (int) $row['payment_stripe_receipt_element_id'];
		$payment_stripe_setup_future_usage  = (int) $row['payment_stripe_setup_future_usage'];
		
		$payment_price_type   = $row['payment_price_type'];
		$payment_price_amount = (float) $row['payment_price_amount'];
		$payment_price_name   = $row['payment_price_name'];

		$payment_enable_recurring = (int) $row['payment_enable_recurring'];
		$payment_recurring_cycle  = (int) $row['payment_recurring_cycle'];
		$payment_recurring_unit   = $row['payment_recurring_unit'];

		$payment_enable_trial = (int) $row['payment_enable_trial'];
		$payment_trial_period = (int) $row['payment_trial_period'];
		$payment_trial_unit   = $row['payment_trial_unit'];
		$payment_trial_amount = (float) $row['payment_trial_amount'];

		$payment_enable_setupfee = (int) $row['payment_enable_setupfee'];
		$payment_setupfee_amount = (float) $row['payment_setupfee_amount'];

		$customer_balance = 0;
		if(!empty($payment_enable_recurring) && !empty($payment_enable_setupfee) && !empty($payment_setupfee_amount)){
			$customer_balance = $payment_setupfee_amount * 100;
		}

		$payment_enable_discount 	 = (int) $row['payment_enable_discount'];
		$payment_discount_type 	 	 = $row['payment_discount_type'];
		$payment_discount_amount 	 = (float) $row['payment_discount_amount'];
		$payment_discount_element_id = (int) $row['payment_discount_element_id'];

		$payment_delay_notifications = (int) $row['payment_delay_notifications'];

		if(!empty($row['form_name'])){
			$form_name = str_replace('&amp;','&',strip_tags($row['form_name']));
			$form_name = mf_trim_max_length($form_name,90);
		}else{
			$form_name = '-Untitled Form- (#'.$form_id.')';
		}
	}

	//check if the form is having payment enabled and using stripe
	if(empty($payment_enable_merchant) || $payment_merchant_type != 'stripe'){		
		echo json_encode([
			'status' => 'error',
			'message' => 'Error. Stripe is not enabled on this form.'
		]);
		
		exit;
	}

	//check if webhook endpoint is configured or not
	if(empty($payment_stripe_live_webhook_id) || empty($payment_stripe_test_webhook_id)){
		mf_ensure_stripe_webhook_endpoint($dbh,$form_id);
	}

	//calculate payment amount
	if($payment_price_type == 'fixed'){ 
			
		$charge_amount = $payment_price_amount * 100; //charge in cents
	}else if($payment_price_type == 'variable'){ 
			
		$charge_amount = (float) mf_get_payment_total($dbh,$form_id,$payment_record_id,0,'live');
		$charge_amount = $charge_amount * 100;
	}

	//if the discount element for the current entry_id having any value, we can be certain that the discount code has been validated and applicable
	$is_discount_applicable = false;
	if(!empty($payment_enable_discount)){
		$query = "select element_{$payment_discount_element_id} coupon_element from ".MF_TABLE_PREFIX."form_{$form_id} where `id` = ? and `status` = 1";
		$params = array($payment_record_id);
		
		$sth = mf_do_query($query,$params,$dbh);
		$row = mf_do_fetch_result($sth);
		
		if(!empty($row['coupon_element'])){
			$is_discount_applicable = true;
		}
	}

	//calculate discount if applicable
	if($is_discount_applicable){
		$payment_calculated_discount = 0;

		if($payment_discount_type == 'percent_off'){
			//the discount is percentage
			$payment_calculated_discount = ($payment_discount_amount / 100) * $charge_amount;
			$payment_calculated_discount = round($payment_calculated_discount); //we need to round it without decimal, since stripe only accept charges in cents, without any decimal 
		}else{
			//the discount is fixed amount
			//multiple it with 100 to charge in cents
			$payment_calculated_discount = round($payment_discount_amount * 100); //we need to round it without decimal, since stripe only accept charges in cents, without any decimal 
		}

		$charge_amount -= $payment_calculated_discount;
	}

	//calculate tax if enabled
	if(!empty($payment_enable_tax) && !empty($payment_tax_rate)){
		$payment_tax_amount = ($payment_tax_rate / 100) * $charge_amount;
		$payment_tax_amount = round($payment_tax_amount); //we need to round it without decimal, since stripe only accept charges in cents, without any decimal 
		$charge_amount += $payment_tax_amount;
	}

	//if stripe email receipt being enabled, get the customer email address
	$customer_email = null;
	if(!empty($payment_stripe_enable_receipt) && !empty($payment_stripe_receipt_element_id)){
		$query = "select `element_{$payment_stripe_receipt_element_id}` customer_email from ".MF_TABLE_PREFIX."form_{$form_id} where `id` = ? and `status` = 1";
		$params = array($payment_record_id);
		
		$sth = mf_do_query($query,$params,$dbh);
		$row = mf_do_fetch_result($sth);

		if(!empty($row['customer_email'])){
			$customer_email = $row['customer_email'];
		}
	}

	//initialize Stripe
	if(!empty($payment_stripe_enable_test_mode)){
		$stripe_secret_key = $payment_stripe_test_secret_key;
	}else{
		$stripe_secret_key = $payment_stripe_live_secret_key;
	}

	$stripe = new \Stripe\StripeClient([
		'api_key' => $stripe_secret_key
	]);

	//create the Customer object in Stripe
	$customer_desc = "Customer for (Form #{$form_id} - Entry #{$payment_record_id})";
	$customer = $stripe->customers->create([
		'description' => $customer_desc,
		'email' => $customer_email,
		'balance' => $customer_balance
	]);

	if(empty($payment_enable_recurring)){
		//if this is one-time payment

		//prepare default charge description
		$charge_desc = "Payment for (Form #{$form_id} - Entry #{$payment_record_id})";
		
		//if stripe email receipt enabled, use the price name as the charge description
		//since this will be displayed within the email receipt
		if(!empty($payment_price_name) && !empty($payment_stripe_enable_receipt)){
			$charge_desc = $payment_price_name;
		}

		//create payment intent
		$payment_intent_params = [
			'amount'                    => $charge_amount,
			'currency'                  => $payment_currency,
			'description' 				=> $charge_desc,
			'customer'                  => $customer->id,
			'metadata' => [
				'Form ID' => $form_id,
				'Entry Number' => $payment_record_id,
				'Form Name' => $form_name
			],
			'automatic_payment_methods' => [
				'enabled' => true
			],
		];
		
		if(!empty($payment_stripe_setup_future_usage)){
			$payment_intent_params['setup_future_usage'] = 'off_session';
		}
		
		if(!empty($customer_email)) {
			$payment_intent_params['receipt_email'] = $customer_email;
		}
		
		$payment_intent = $stripe->paymentIntents->create($payment_intent_params);
		$client_secret = $payment_intent->client_secret;
		$confirm_type = 'payment';
	}else{
		//if this is recurring payment

		//prepare default plan description
		$plan_desc = "Plan for (Form #{$form_id} - Entry #{$payment_record_id})";
		
		//if stripe email receipt enabled, use the price name as the plan description
		//since this will be displayed within the email receipt
		if(!empty($payment_price_name) && !empty($payment_stripe_enable_receipt)){
			$plan_desc = $payment_price_name;
		}

		//if there is trial period
		$trial_period_days = 0;
		if(!empty($payment_enable_trial)){
			if($payment_trial_unit == 'day'){
				$trial_period_days = $payment_trial_period;
			}else if($payment_trial_unit == 'week'){
				$trial_period_days = $payment_trial_period * 7;
			}else if($payment_trial_unit == 'month'){
				$trial_period_days = $payment_trial_period * 30;
			}else if($payment_trial_unit == 'year'){
				$trial_period_days = $payment_trial_period * 365;
			}

			//if paid trial enabled, create an invoice item
			if(!empty($payment_trial_amount)){
				$trial_charge_amount = $payment_trial_amount * 100; //charge in cents
					
				//prepare default trial description
				$trial_charge_desc = "Trial Period Payment for (Form #{$form_id} - Entry #{$payment_record_id})";
				
				//if stripe email receipt enabled, use the price name as the plan description
				//since this will be displayed within the email receipt
				if(!empty($payment_price_name) && !empty($payment_stripe_enable_receipt)){
					$trial_charge_desc = $payment_price_name.' (Trial Period)';
				}

				$stripe->invoiceItems->create([
					'customer'    => $customer->id,
					'amount'      => $trial_charge_amount,
					'currency'    => $payment_currency,
					'description' => $trial_charge_desc,
				]);
			}
		}

		//create the price 
		$price = $stripe->prices->create([
			'currency' => $payment_currency,
			'unit_amount' => $charge_amount,
			'recurring' => [
				'interval' => $payment_recurring_unit,
				'interval_count' => $payment_recurring_cycle
			],
			'product_data' => ['name' => $plan_desc],
		]);
	
		//create the subscription
		$subscription = $stripe->subscriptions->create([
			'customer' => $customer->id,
			'items' => [[
				'price' => $price->id,
			]],
			'metadata' => [
				'Form ID' => $form_id,
				'Entry Number' => $payment_record_id,
				'Form Name' => $form_name
			],
			'trial_period_days' => $trial_period_days,
			'payment_behavior' => 'default_incomplete',
			'payment_settings' => ['save_default_payment_method' => 'on_subscription'],
			'expand' => ['latest_invoice.payment_intent', 'pending_setup_intent'],
		]);

		//if there is PaymentIntent, update the PaymentIntent with metadata
		//this happens when a subscription is charged immediately
		if(!empty($subscription->latest_invoice->payment_intent->id)){
			$stripe->paymentIntents->update($subscription->latest_invoice->payment_intent->id, [
				'metadata' => [
					'Form ID' => $form_id,
					'Entry Number' => $payment_record_id,
					'Form Name' => $form_name
				],
			]);
		}

		//if there is SetupIntent, update the SetupIntent with metadata
		//this happens when the subscription is having free trial period
		if(!empty($subscription->pending_setup_intent->id)){
			$stripe->setupIntents->update($subscription->pending_setup_intent->id, [
				'metadata' => [
					'Form ID' => $form_id,
					'Entry Number' => $payment_record_id,
					'Form Name' => $form_name
				],
			]);
		}
		
		if($subscription->pending_setup_intent !== NULL) {
			$client_secret = $subscription->pending_setup_intent->client_secret;
			$confirm_type = 'setup';
		}else{
			$client_secret = $subscription->latest_invoice->payment_intent->client_secret;
			$confirm_type = 'payment';
		}
	}
	
    
    echo json_encode([
		'status' => 'ok',
        'client_secret' => $client_secret,
		'type' => $confirm_type
    ]);
