<?php

namespace PaychefPaymentGateway\Service;

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

use Exception;
use Paychef\Models\Response\Transaction;
use PaychefPaymentGateway\Util\BasketUtil;

class PaychefApiService
{
    private $instance;
    private $apiKey;
    private $platform;
    private $lookAndFeelId;

    /**
     * Constructor
     *
     * @param EntityRepository $customerRepository
     * @param LoggerInterface $logger
     */
    public function __construct($instance, $apiKey, $platform, $lookAndFeelId)
    {
        $this->instance = $instance;
        $this->apiKey = $apiKey;
        $this->platform = $platform;
        $this->lookAndFeelId = $lookAndFeelId;
    }

    public function createPaychefGateway($order, $cart, $totalAmount, $pm, $reference, $successRedirectUrl, $cancelRedirectUrl, $preAuthorization, $chargeOnAuth) {
        $paychef = $this->getInterface();
        $gateway = new \Paychef\Models\Request\Gateway();

        $gateway->setValidity(15);
        $gateway->setPsp([]);
        $gateway->setSkipResultPage(true);

        $totalAmount = round($totalAmount, 2);
        if ($totalAmount) {
            $gateway->setAmount($totalAmount * 100);
        } else {
            // The amount is artificially elevated because the Gateway creation always needs an amount
            $gateway->setAmount(0.50 * 100);
        }

        if (!$totalAmount && $preAuthorization) {
            $gateway->setButtonText([
                1 => 'Autorisieren',
                2 => 'Authorize',
                3 => 'Autoriser',
                4 => 'Autorizzare',
                7 => 'Autoriseer',
            ]);
        }

        $gateway->setCurrency(get_woocommerce_currency() ?: 'USD');

        $gateway->setPm([$pm]);
        $gateway->setPreAuthorization($preAuthorization);
        $gateway->setChargeOnAuthorization($chargeOnAuth);

        $basket = BasketUtil::createBasketByCart($cart);
        $basketAmount = round(BasketUtil::getBasketAmount($basket), 2);
        
        if (!empty($basket) && $totalAmount && $totalAmount === $basketAmount) {
            $gateway->setBasket($basket);
        } else {
            // For add_payment_method or when basket doesn't match, set a simple purpose
            if (!empty($basket)) {
                $gateway->setPurpose([BasketUtil::createPurposeByBasket($basket)]);
            } else {
                $gateway->setPurpose(['Add Payment Method']);
            }
        }

        $gateway->setReferenceId($reference);

        $gateway->setLookAndFeelProfile($this->lookAndFeelId ?: null);

        $gateway->setSuccessRedirectUrl($successRedirectUrl);
        $gateway->setCancelRedirectUrl($cancelRedirectUrl);
        $gateway->setFailedRedirectUrl($cancelRedirectUrl);

        // Add billing information if order exists
        if ($order) {
            $billingAddress = $order->get_billing_address_1() . ' ' . $order->get_billing_address_2();
            $gateway->addField('title', '');
            $gateway->addField('forename', $order->get_billing_first_name());
            $gateway->addField('surname', $order->get_billing_last_name());
            $gateway->addField('company', $order->get_billing_company());
            $gateway->addField('street', $billingAddress);
            $gateway->addField('postcode', $order->get_billing_postcode());
            $gateway->addField('place', $order->get_billing_city());
            $gateway->addField('country', $order->get_billing_country());
            $gateway->addField('phone', $order->get_billing_phone());
            $gateway->addField('email', $order->get_billing_email());
            $gateway->addField('custom_field_1', $order->get_id(), 'WooCommerce Order ID');
        } else {
            // For add_payment_method, use current user data
            $current_user = wp_get_current_user();
            $gateway->addField('title', '');
            $gateway->addField('forename', $current_user->first_name);
            $gateway->addField('surname', $current_user->last_name);
            $gateway->addField('company', '');
            $gateway->addField('street', '');
            $gateway->addField('postcode', '');
            $gateway->addField('place', '');
            $gateway->addField('country', '');
            $gateway->addField('phone', '');
            $gateway->addField('email', $current_user->user_email);
            $gateway->addField('custom_field_1', 'Add Payment Method', 'Action');
        }

        try {
            $response = $paychef->create($gateway);
            return $response;
        } catch (\Paychef\PaychefException $e) {
            return null;
        }
    }

    public function deleteGatewayById($gatewayId):bool {
        $paychef = $this->getInterface();

        $gateway = new \Paychef\Models\Request\Gateway();
        $gateway->setId($gatewayId);

        try {
            $paychef->delete($gateway);
        } catch (\Paychef\PaychefException $e) {
            return false;
        }
        return true;
    }

    public function getPaychefTransaction(int $paychefTransactionId): ?\Paychef\Models\Response\Transaction
    {
        $paychef = $this->getInterface();

        $paychefTransaction = new \Paychef\Models\Request\Transaction();
        $paychefTransaction->setId($paychefTransactionId);

        try {
            $response = $paychef->getOne($paychefTransaction);
            return $response;
        } catch (\Paychef\PaychefException $e) {
            return null;
        }
    }

    public function chargeTransaction($transactionId, $amount) {
        $paychef = $this->getInterface();
        $transaction = new \Paychef\Models\Request\Transaction();
        $transaction->setId($transactionId);
        $transaction->setAmount(floatval($amount) * 100);
        try {
            $response = $paychef->charge($transaction);
            return $response; // Return the full response object
        } catch (\Paychef\PaychefException $e) {
            error_log('Paychef charge error: ' . $e->getMessage());
        }
        return false;
    }


    /**
     * @param $gatewayId
     * @return \Paychef\Models\Request\Gateway
     */
    public function getPaychefGateway($gatewayId) {
        $paychef = $this->getInterface();
        $gateway = new \Paychef\Models\Request\Gateway();
        $gateway->setId($gatewayId);
        try {
            $paychefGateway = $paychef->getOne($gateway);
            return $paychefGateway;
        } catch (\Paychef\PaychefException $e) {
            throw new \Exception('No gateway found by ID: ' . $gatewayId);
        }
    }

    /**
     * Refund transaction
     *
     * @param string $gateway_id paychef gateway id.
     * @param string $transaction_uuid transaction uuid.
     * @param float $amount refund amount.
     */
	public function refund_transaction( $gateway_id, $transaction_uuid, $amount ) {
        try {
            $paychef_gateway = $this->getPaychefGateway($gateway_id);
            $invoices = $paychef_gateway->getInvoices();

            if (!$invoices || !$invoice = end($invoices)) {
                return false;
            }

            $transactions = $invoice['transactions'];
            if (!$transactions) {
                return false;
            }
            $transaction_id = '';
            foreach ($transactions as $transaction) {
                if ($transaction['uuid'] === $transaction_uuid) {
                    $transaction_id = $transaction['id'];
                    break;
                }

                // fix: if uuid not exists.
                if (Transaction::CONFIRMED === $transaction['status']) {
                    $transaction_id = $transaction['id'];
                    break;
                }
            }

            $refund_transaction = $this->getPaychefTransaction($transaction_id);
            if ($refund_transaction->getStatus() === Transaction::CONFIRMED) {
                $paychef = $this->getInterface();
                $transaction = new \Paychef\Models\Request\Transaction();
                $transaction->setId($refund_transaction->getId());
                $transaction->setAmount((int)($amount * 100));
                $refund = $paychef->refund($transaction);
                $refund_success_status = [
                    Transaction::CONFIRMED,
                    Transaction::REFUNDED,
                    Transaction::PARTIALLY_REFUNDED,
                ];
                if (in_array($refund->getStatus(), $refund_success_status)) {
                    return true;
                }
            }
            return false;
        } catch (\Paychef\PaychefException $e) {
            return false;
        }
    }

	public function validate_api_credentials($instance, $apiKey, $platform)
	{
		$paychef = new \Paychef\Paychef($instance, $apiKey, '', $platform);
		$signatureCheck = new \Paychef\Models\Request\SignatureCheck();

		try {
			$response = $paychef->getOne($signatureCheck);
		} catch(\Paychef\PaychefException $e) {
			return false;
		}

		return true;
	}

	/**
	 * @return \Paychef\Paychef
	 */
	private function getInterface(): \Paychef\Paychef
	{
		$platform = !empty($this->platform) ? $this->platform : \Paychef\Communicator::API_URL_BASE_DOMAIN;
		return new \Paychef\Paychef($this->instance, $this->apiKey, '', $platform);
	}
}
