<?php

namespace BitCode\BitFormPro\API\Controller;

use BitCode\BitForm\Core\Database\FormEntryMetaModel;
use BitCode\BitForm\Core\Util\Log;
use BitCode\BitFormPro\Core\Database\PaymentInfoModel;
use BitCode\BitForm\Core\Database\FormEntryModel;
use BitCode\BitForm\Admin\Form\AdminFormHandler;
use BitCode\BitForm\Core\Form\FormManager;
use BitCode\BitForm\Core\Integration\IntegrationHandler;
use Exception;
use WP_Error;

/**
 * Abstract base class for handling payment services.
 *
 * Provides a generic structure for integrating different payment gateways
 * (e.g., PayPal, Stripe, Mollie, Razorpay) with BitForm.
 * Handles saving payment metadata, inserting payment records,
 * and triggering both global and gateway-specific hooks.
 *
 * Child classes only need to set the properties (formId, entryId, etc.)
 * instead of passing them as method arguments.
 *
 * @package BitCode\BitFormPro\API\Controller
 */
abstract class PaymentServices
{
  protected $formMetaModel;

  protected $paymentModel;

  /** @var string Gateway name (paypal, stripe, mollie, razorpay) */
  protected $paymentName = '';

  /** @var string Payment type (order, subscription, one_time) */
  protected $paymentType = '';

  // 🔥 Global payment context (set by child classes)
  protected $formId;
  protected $entryId;
  protected $fieldKey;
  protected $transactionId;
  protected $apiResponseData;

  public function __construct()
  {
    $this->paymentModel = new PaymentInfoModel();
    $this->formMetaModel = new FormEntryMetaModel();
  }

  /**
   * Handle the payment flow for the gateway.
   *
   * This method should process the payment and then call $this->savePaymentInfo().
   *
   * @return mixed
   */
  abstract public function handlePayment();

  /**
   * Saves payment information to database.
   *
   * Uses the globally set properties ($formId, $entryId, $fieldKey, $transactionId, $apiResponseData).
   *
   * @return null Insert ID of payment record on success, false on duplicate.
   */
  protected function savePaymentInfo()
  {
    $encodeApiResponse = is_array($this->apiResponseData)
      || is_object($this->apiResponseData)
      ? wp_json_encode($this->apiResponseData)
      : $this->apiResponseData;

    // Check duplicate transaction
    $existMetaData = $this->formMetaModel->isEntryMetaExist([
      'bitforms_form_entry_id' => $this->entryId,
      'meta_key' => $this->fieldKey,
      'meta_value' => $this->transactionId,
    ]);

    if (!$existMetaData) {
      // Insert metadata
      $this->formMetaModel->insert([
        'bitforms_form_entry_id' => $this->entryId,
        'meta_key' => $this->fieldKey,
        'meta_value' => $this->transactionId,
      ]);

      // Insert payment record
      $insertId = $this->paymentModel->paymentInsert(
        $this->formId,
        $this->transactionId,
        $this->paymentName,
        $this->paymentType,
        $encodeApiResponse
      );

      if ($insertId) {
        // run workflow
        $this->runWorkFlowAfterPayment();
        $this->triggerTransactionSuccess();
        return $insertId;
      }

      // Fire success hooks

    } else {
      $getPaymentInfo = $this->paymentModel->paymentDetail($this->formId, $this->transactionId)[0];

      $payment_response = is_string($getPaymentInfo->payment_response) ? json_decode($getPaymentInfo->payment_response) : $getPaymentInfo->payment_response;

      if ($payment_response->status === 'authorized') {
        $insertId = $this->paymentModel->paymentInsert(
          $this->formId,
          $this->transactionId,
          $this->paymentName,
          $this->paymentType,
          $encodeApiResponse
        );
        if ($insertId) {
          return $insertId;
        }
      }
      Log::debug_log("[{$this->paymentName}] Duplicate transaction skipped: {$this->transactionId}");
    }
    Log::debug_log("[{$this->paymentName}] Duplicate transaction skipped: {$this->transactionId}");
  }

  /**
   * Update Entry Status
   * Sets the status of a form entry to the specified value.
   * 
   * @param int $formId The ID of the form.
   * @param int $entryId The ID of the entry.
   * @param int $status The status to set (default is 0). e.g. 0 = Read, 1 = Unread, 2 = Unconfirmed, 3 = Confirmed, 9 = Draft
   * @return void|WP_Error
   */
  protected function updateEntryStatus($formId, $entryId, $status = 0)
  {
    $formEntryModel = new FormEntryModel();
    $updatedTime = current_time('mysql');

    $status = $formEntryModel->update(
      [
        'status' => 1,
        'updated_at' => $updatedTime,
      ],
      [
        'form_id' => $formId,
        'id' => $entryId,
      ]
    );

    if (is_wp_error($status)) {
      Log::debug_log("Failed to update entry status for Entry ID: {$entryId}, Form ID: {$formId}. Error: " . $status->get_error_message());

      return new WP_Error(
        'status_error',
        __("Failed to update entry status for Entry ID: {$entryId}, Form ID: {$formId}. Error: " . $status->get_error_message(), 'bit-form')
      );
    } else {
      Log::debug_log("Entry status updated to '0' for Entry ID: {$entryId}, Form ID: {$formId}");
    }
  }

  /**
   * Triggers success hooks after a successful payment.
   *
   * @return void
   */
  protected function triggerTransactionSuccess()
  {
    // Gateway-specific hook
    do_action("bitform_{$this->paymentName}_transaction_success", $this->formId, $this->entryId, $this->fieldKey, $this->apiResponseData);

    // Global hook
    do_action('bitform_payment_transaction_success', $this->formId, $this->entryId, $this->fieldKey, $this->paymentName, $this->paymentType, $this->apiResponseData);
  }

  /**
   * Triggers failure hooks when a payment fails.
   *
   * @param string $reason Reason or error message.
   * @return void
   */
  protected function triggerTransactionFailure($reason = '')
  {
    $data = [
      'form_id' => $this->formId,
      'entry_id' => $this->entryId,
      'field_key' => $this->fieldKey,
      'transaction_id' => $this->transactionId,
      'payment_name' => $this->paymentName,
      'payment_type' => $this->paymentType,
      'api_response' => $this->apiResponseData,
      'reason' => $reason,
    ];

    // Gateway-specific hook
    do_action("bitform_{$this->paymentName}_transaction_failed", $this->formId, $this->entryId, $this->fieldKey, $this->apiResponseData, $reason);

    // Global hook
    do_action('bitform_payment_transaction_failed', $this->formId, $this->entryId, $this->fieldKey, $this->paymentName, $this->paymentType, $this->apiResponseData, $reason);
  }

  public function triggerTransitionSuccessFilter()
  {
    return apply_filters("bitform_{$this->paymentName}_transaction_success", $this->formId, $this->entryId, $this->fieldKey, $this->apiResponseData);

  }

  public function runWorkFlowAfterPayment()
  {
    try {
      $adminFormHandler = new AdminFormHandler();

      $getEntry = $adminFormHandler->getSingleEntry($this->formId, $this->entryId);

      if (is_wp_error($getEntry)) {
        Log::debug_log($getEntry->get_error_message());
        return false;
      }

      if (is_array($getEntry)) {
        $getEntry = (object) $getEntry;
      }

      $formManager = new FormManager($this->formId);

      $updateFormEntry = $formManager->updateFormEntry($getEntry, $this->formId, $this->entryId);

      IntegrationHandler::maybeSetCronForIntegration((array) $updateFormEntry, 'create');

      return true;

    } catch (Exception $e) {
      Log::debug_log('Workflow run issue: ' . $e->getMessage());
      return false;
    }

  }


  protected function sanitize($data)
  {
    return sanitize_text_field($data);
  }
}