<?php

namespace PaychefPaymentGateway\Service;

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

use Paychef\Models\Response\Transaction;
use WC_Payment_Token_CC;
use WC_Payment_Tokens;

class OrderService
{
    const WC_STATUS_CANCELLED = 'cancelled';
    const WC_STATUS_FAILED = 'failed';
    const WC_STATUS_REFUNDED = 'refunded';
    const WC_STATUS_PROCESSING = 'processing';
    const WC_STATUS_COMPLETED = 'completed';
    const WC_STATUS_ONHOLD = 'on-hold';
    const WC_STATUS_PENDING = 'pending';

    const STATUS_MESSAGES = [
        self::WC_STATUS_CANCELLED => 'Payment was cancelled by the customer',
        self::WC_STATUS_FAILED => 'An error occured while processing this payment',
        self::WC_STATUS_REFUNDED => 'Payment was fully refunded',
        self::WC_STATUS_ONHOLD => 'Awaiting payment',
        Transaction::PARTIALLY_REFUNDED => 'Payment was partially refunded',
    ];

    /**
     * Get translated status message
     *
     * @param string $status The status key
     * @return string Translated status message
     */
    public function getTranslatedStatusMessage($status)
    {
        $messages = [
            self::WC_STATUS_CANCELLED => __('Payment was cancelled by the customer', 'paychef-payments-for-woocommerce'),
            self::WC_STATUS_FAILED => __('An error occurred while processing this payment', 'paychef-payments-for-woocommerce'),
            self::WC_STATUS_REFUNDED => __('Payment was fully refunded', 'paychef-payments-for-woocommerce'),
            self::WC_STATUS_ONHOLD => __('Awaiting payment', 'paychef-payments-for-woocommerce'),
            Transaction::PARTIALLY_REFUNDED => __('Payment was partially refunded', 'paychef-payments-for-woocommerce'),
        ];

        return $messages[$status] ?? __('Unknown status', 'paychef-payments-for-woocommerce');
    }

    /**
     * Handle transaction status
     *
     * @param Order $order Order.
     * @param array $subscriptions subscriptions.
     * @param string $paychef_status paychef transaction status.
     * @param string $transaction_uuid paychef transaction uuid.
     * @param string $pre_auth_id preauth id.
     * @return void
     */
    public function handleTransactionStatus($order, array $subscriptions, $paychef_status, $transaction_uuid, $pre_auth_id = '', $additionalData = [])
    {
        $order_status = '';

        switch ($paychef_status) {
            case Transaction::WAITING:
                $order_status = self::WC_STATUS_ONHOLD;
                break;
            case Transaction::CONFIRMED:
                if ($order->has_status(['processing', 'completed']) && !empty($order->get_meta('paychef_real_transaction_id', true))) {
                    $this->checkForDoubleBilling($order, $transaction_uuid);
                    return;
                }
                if ($order->has_status(['processing', 'completed'])) {
                    error_log("Order already processed. Skipping.");
                    return;
                }
                $message = sprintf( __( 'Paychef charge complete (Charge ID: %s)', 'paychef-payments-for-woocommerce' ), $transaction_uuid );
                $order->add_order_note( $message );

                if (!empty($pre_auth_id)) {
                    $user_id = $order->get_user_id();
                    $order->update_meta_data('_paychef_pre_authorization_id', $pre_auth_id);
                    $order->update_meta_data('_paychef_card', $additionalData['payment']['cardNumber'] ?? '');

                    $save_payment_method = $order->get_meta('_save_payment_method') === 'yes' || $order->get_meta('paychef_save_payment_method', true);

                    if ($save_payment_method && !$this->is_card_already_saved($user_id, $order->get_payment_method(), $additionalData)) {
                        $saved_token = $this->save_payment_token($order, $pre_auth_id, $additionalData);
                    }

                    // Überprüfen, ob die Bestellung bereits abgerechnet wurde
                    if ($order->get_meta('_paychef_charge_attempted') !== 'yes') {
                        $order->update_meta_data('_paychef_charge_attempted', 'yes');
                        $order->save();

                        $payment_method = $order->get_payment_method();
                        $payment_gateways = WC()->payment_gateways->payment_gateways();

                        if (isset($payment_gateways[$payment_method])) {
                            $gateway = $payment_gateways[$payment_method];

                            if (method_exists($gateway, 'charge_transaction')) {
                                $result = $gateway->charge_transaction($order, $pre_auth_id);
                                if (!$result) {
                                    $order->update_status('failed', __('Failed to charge payment.', 'paychef-payments-for-woocommerce'));
                                    return;
                                }
                            }
                        }
                    }
                }

                $this->setOrderPaid($order, $transaction_uuid);
                return;
            case Transaction::AUTHORIZED:
                $payment_method = $order->get_payment_method();
                $payment_gateways = WC()->payment_gateways->payment_gateways();

                if (isset($payment_gateways[$payment_method])) {
                    $gateway = $payment_gateways[$payment_method];

                    if (method_exists($gateway, 'charge_transaction')) {
                        $result = $gateway->charge_transaction($order, $pre_auth_id);
                        if ($result) {
                            $this->setOrderPaid($order, $transaction_uuid);
                        } else {
                            $order->update_status('failed', __('Failed to charge authorized payment.', 'paychef-payments-for-woocommerce'));
                        }
                    } else {
                        $order->update_status('on-hold', __('Payment authorized but automatic charge not available.', 'paychef-payments-for-woocommerce'));
                    }
                } else {
                    $order->update_status('on-hold', __('Payment authorized but gateway not found for charge.', 'paychef-payments-for-woocommerce'));
                }
                break;
            case Transaction::REFUNDED:
                $order_status = self::WC_STATUS_REFUNDED;
                break;
            case Transaction::PARTIALLY_REFUNDED:
                if ($order->get_status() === self::WC_STATUS_REFUNDED) {
                    break;
                }
                $order->add_order_note(
                    self::STATUS_MESSAGES[$paychef_status] . ' ( ' . $transaction_uuid . ' )'
                );
                return;
            case Transaction::CANCELLED:
            case Transaction::EXPIRED:
            case Transaction::DECLINED:
                $order_status = self::WC_STATUS_CANCELLED;
                break;
            case Transaction::ERROR:
                $order_status = self::WC_STATUS_FAILED;
                break;
        }

        if (!$order_status || !$this->transition_allowed($order_status, $order)) {
            return;
        }

        $comment = $this->generateOrderComment($paychef_status, $transaction_uuid, $additionalData);
        $this->transitionOrder($order, $order_status, $comment);
    }


    private function handleSubscriptionAuthorization($order, $subscriptions, $pre_auth_id, $transaction_uuid)
    {
        foreach ($subscriptions as $subscription) {
            $subscription->update_meta_data('paychef_auth_transaction_id', $pre_auth_id);
            $subscription->save();
        }

        $order->update_meta_data('paychef_pre_authorization_id', $pre_auth_id);

        $initial_payment = $order->get_total();
        if ($initial_payment > 0) {
            $this->capturePartialPayment($order, $pre_auth_id, $initial_payment, $transaction_uuid);
        } else {
            $this->setOrderPaid($order, $transaction_uuid);
        }
    }

    private function handleTokenPayment($order, $pre_auth_id, $transaction_uuid)
    {
        $payment_method = $order->get_payment_method();
        $payment_gateways = WC()->payment_gateways->payment_gateways();

        if (isset($payment_gateways[$payment_method])) {
            $gateway = $payment_gateways[$payment_method];

            if (method_exists($gateway, 'charge_transaction')) {
                $result = $gateway->charge_transaction($order, $pre_auth_id);
                if ($result) {
                    $this->setOrderPaid($order, $transaction_uuid);
                } else {
                    $order->update_status('failed', __('Failed to charge token payment.', 'paychef-payments-for-woocommerce'));
                }
            } else {
                $order->update_status('on-hold', __('Token payment authorized but automatic charge not available.', 'paychef-payments-for-woocommerce'));
            }
        } else {
            $order->update_status('on-hold', __('Token payment authorized but gateway not found for charge.', 'paychef-payments-for-woocommerce'));
        }
    }

    private function captureAuthorizedPayment($order, $pre_auth_id, $transaction_uuid)
    {
        $payment_method = $order->get_payment_method();
        $payment_gateways = WC()->payment_gateways->payment_gateways();

        if (isset($payment_gateways[$payment_method])) {
            $gateway = $payment_gateways[$payment_method];

            if (method_exists($gateway, 'capture_payment')) {
                $result = $gateway->capture_payment($order, $pre_auth_id);
                if ($result) {
                    $this->setOrderPaid($order, $transaction_uuid);
                } else {
                    $order->update_status('failed', __('Failed to capture authorized payment.', 'paychef-payments-for-woocommerce'));
                }
            } else {
                $order->update_status('on-hold', __('Payment authorized but automatic capture not available.', 'paychef-payments-for-woocommerce'));
            }
        } else {
            $order->update_status('on-hold', __('Payment authorized but gateway not found for capture.', 'paychef-payments-for-woocommerce'));
        }
    }


    private function capturePartialPayment($order, $pre_auth_id, $amount, $transaction_uuid)
    {
        $payment_method = $order->get_payment_method();
        $payment_gateways = WC()->payment_gateways->payment_gateways();

        if (isset($payment_gateways[$payment_method])) {
            $gateway = $payment_gateways[$payment_method];

            if (method_exists($gateway, 'capture_partial_payment')) {
                $result = $gateway->capture_partial_payment($order, $pre_auth_id, $amount);
                if ($result) {
                    $this->setOrderPaid($order, $transaction_uuid);
                } else {
                    $order->update_status('failed', __('Failed to capture initial subscription payment.', 'paychef-payments-for-woocommerce'));
                }
            }
        }
    }

    private function generateOrderComment($status, $transaction_uuid, $additionalData)
    {
        $statusMessage = self::STATUS_MESSAGES[$status] ?? 'Unknown status';
        $paymentMethod = $additionalData['payment_brand'] ?? '';
        $psp = $additionalData['psp'] ?? '';

        return sprintf(
            __('%s via %s (%s). PSP: %s, Transaction ID: %s', 'paychef-payments-for-woocommerce'),
            $statusMessage,
            $paymentMethod,
            $status,
            $psp,
            $transaction_uuid
        );
    }

    /**
     * Check order transition allowed
     *
     * @param string $new_status new order status.
     * @param WC_Order $order woocommerce order.
     * @return bool
     */
	public function transition_allowed( string $new_status, $order ): bool {
		$old_status = $order->get_status();

		if ( $new_status === $old_status ||
		     (
			     $order->get_transaction_id() && // Check paid
			     $new_status !== self::WC_STATUS_REFUNDED // Refund allowed
		     )
		) {
			return false;
		}
        switch ($new_status) {
            case self::WC_STATUS_CANCELLED:
            case self::WC_STATUS_FAILED:
                return in_array($old_status, [self::WC_STATUS_PENDING, self::WC_STATUS_ONHOLD]);
            case self::WC_STATUS_PROCESSING:
                return !in_array($old_status, [self::WC_STATUS_COMPLETED, self::WC_STATUS_REFUNDED]);
            case self::WC_STATUS_REFUNDED:
                return in_array($old_status, [self::WC_STATUS_PROCESSING, self::WC_STATUS_COMPLETED]);
            case self::WC_STATUS_ONHOLD:
                return self::WC_STATUS_PENDING === $old_status;
        }
		return false;
    }

    /**
     * Transition the order
     *
     * @param order $order order.
     * @param string $order_status order status.
     * @param string $transaction_uuid paychef transaction uuid.
     * @return void
     */
    public function transitionOrder($order, string $order_status, string $transaction_uuid = '')
    {
        $custom_status = apply_filters('woo_paychef_custom_transaction_status_' . $order_status, $order_status);
        if ($transaction_uuid) {
            $transaction_uuid = ' ( ' . $transaction_uuid . ' )';
        }
        $order->update_status(
            $custom_status,
            $this->getTranslatedStatusMessage($order_status) . $transaction_uuid
        );
    }

    /**
     * @param $order
     * @param $transactionUuid
     * @return void
     */
    private function setOrderPaid($order, $transaction_uuid)
    {
	    if ( ! $this->transition_allowed( self::WC_STATUS_PROCESSING, $order ) ) {
		    return;
	    }

        if ($order->get_meta('_paychef_payment_completed') !== 'yes') {
            $order->update_meta_data('_paychef_payment_completed', 'yes');
            $order->payment_complete($transaction_uuid);
            $order->add_order_note(__('Payment completed.', 'paychef-payments-for-woocommerce'));
            WC()->cart->empty_cart();
        }
    }

    private function save_payment_token($order, $token, $additionalData)
    {
        $user_id = $order ? $order->get_user_id() : get_current_user_id();
        $payment_method = $order ? $order->get_payment_method() : '';

        try {
            $token_obj = new WC_Payment_Token_CC();
            $token_obj->set_token($token);
            $token_obj->set_gateway_id($payment_method);
            $token_obj->set_card_type($additionalData['payment']['brand'] ?? '');
            $token_obj->set_last4(substr($additionalData['payment']['cardNumber'] ?? '', -4));
            $expiry = explode('-', $additionalData['payment']['expiry'] ?? '');
            $token_obj->set_expiry_month($expiry[1] ?? '');
            $token_obj->set_expiry_year($expiry[0] ?? '');
            $token_obj->set_user_id($user_id);
            $token_obj->add_meta_data('paychef_auth_transaction_id', $token);

            if ($token_obj->save()) {
                if ($order) {
                    $order->add_payment_token($token_obj);
                }
                
                // Set the newly saved token as default for the user
                $this->set_default_payment_token($user_id, $token_obj);
                
                return $token_obj;
            }
        } catch (Exception $e) {
            error_log('Error saving token: ' . $e->getMessage());
        }
        return null;
    }

    /**
     * Get gateway ID from reference for add_payment_method
     */
    private function getGatewayFromReference($reference) {
        // Extract gateway from reference like "add_payment_method_123_1234567890"
        // This would need to be enhanced based on actual reference format
        return 'paychef'; // Default fallback
    }

    /**
     * Check if card is already saved based on card details instead of token
     */
    private function is_card_already_saved($user_id, $gateway_id, $additionalData) {
        $tokens = WC_Payment_Tokens::get_tokens(array(
            'user_id' => $user_id,
            'gateway_id' => $gateway_id
        ));

        $new_last4 = substr($additionalData['payment']['cardNumber'] ?? '', -4);
        $new_expiry = $additionalData['payment']['expiry'] ?? '';
        $new_brand = $additionalData['payment']['brand'] ?? '';

        foreach ($tokens as $existing_token) {
            if ($existing_token instanceof WC_Payment_Token_CC) {
                // Compare last 4 digits, expiry, and brand
                if ($existing_token->get_last4() === $new_last4 && 
                    $existing_token->get_card_type() === $new_brand) {
                    
                    // Compare expiry (format: 2030-12)
                    $expiry_parts = explode('-', $new_expiry);
                    if (count($expiry_parts) >= 2) {
                        $new_year = $expiry_parts[0];
                        $new_month = $expiry_parts[1];
                        
                        if ($existing_token->get_expiry_year() === $new_year && 
                            $existing_token->get_expiry_month() === $new_month) {
                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }

    private function is_token_exist($token, $user_id, $gateway_id)
    {
        $tokens = WC_Payment_Tokens::get_tokens(array(
            'user_id' => $user_id,
            'gateway_id' => $gateway_id
        ));

        foreach ($tokens as $existing_token) {
            if ($existing_token->get_token() === $token) {
                return true;
            }
        }

        return false;
    }

    /**
     * Set the newest payment token as default for the user
     *
     * @param int $user_id User ID
     * @param WC_Payment_Token_CC $new_token The newly created token
     */
    private function set_default_payment_token($user_id, $new_token) {
        // Get all tokens for this user and gateway
        $tokens = WC_Payment_Tokens::get_tokens(array(
            'user_id' => $user_id,
            'gateway_id' => $new_token->get_gateway_id()
        ));

        // First, set all existing tokens for this gateway as non-default
        foreach ($tokens as $token) {
            if ($token->get_id() !== $new_token->get_id()) {
                $token->set_default(false);
                $token->save();
            }
        }

        // Set the new token as default
        $new_token->set_default(true);
        $new_token->save();
        
    }

    /**
     * Save payment token for user (for add_payment_method requests)
     *
     * @param int $user_id User ID
     * @param string $gateway_id Gateway ID
     * @param string $token Pre-authorization token
     * @param array $additionalData Payment data
     * @return WC_Payment_Token_CC|null
     */
    public function save_payment_token_for_user($user_id, $gateway_id, $token, $additionalData) {
        try {
            // Check if card is already saved to prevent duplicates
            if ($this->is_card_already_saved($user_id, $gateway_id, $additionalData)) {
                return null;
            }

            $token_obj = new WC_Payment_Token_CC();
            $token_obj->set_token($token);
            $token_obj->set_gateway_id($gateway_id);
            $token_obj->set_card_type($additionalData['payment']['brand'] ?? '');
            $token_obj->set_last4(substr($additionalData['payment']['cardNumber'] ?? '', -4));
            
            $expiry = explode('-', $additionalData['payment']['expiry'] ?? '');
            $token_obj->set_expiry_month($expiry[1] ?? '');
            $token_obj->set_expiry_year($expiry[0] ?? '');
            $token_obj->set_user_id($user_id);
            $token_obj->add_meta_data('paychef_auth_transaction_id', $token);

            if ($token_obj->save()) {
                // Set the newly saved token as default for the user
                $this->set_default_payment_token($user_id, $token_obj);
                
                return $token_obj;
            }
        } catch (Exception $e) {
            error_log('Error saving token for add_payment_method: ' . $e->getMessage());
        }
        return null;
    }
}