<?php

namespace Tami\WooCommerce;

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class JWKResource {
	private string $kty = 'oct';
	private string $use = 'sig';
	private string $kid;
	private string $k;
	private string $alg = 'HS512';

	public function __construct(string $kid = '', string $k = '') {
		$this->kid = $kid;
		$this->k = $k;
	}


	public function getKid(): string {
		return $this->kid;
	}

	public function getK(): string {
		return $this->k;
	}

	public function getAlg(): string {
		return $this->alg;
	}

	public function setKid(string $kid): void {
		$this->kid = $kid;
	}

	public function setK(string $k): void {
		$this->k = $k;
	}

	public function toArray(): array {
		return [
			'kty' => $this->kty,
			'use' => $this->use,
			'kid' => $this->kid,
			'k' => $this->k,
			'alg' => $this->alg
		];
	}
}

class HashGenerator {
	private $merchant_id;
	private $terminal_id;
	private $secret_key;
	private $fixed_k_value;
	private $fixed_kid_value;
    private $api_v3_enabled = false;

	public function __construct(
		$merchantId,
		$terminalId,
		$secretKey,
		$kidValue,
		$kValue
	) {
		$this->merchant_id     = $merchantId;
		$this->terminal_id     = $terminalId;
		$this->secret_key      = $secretKey;
		$this->fixed_k_value   = $kValue;
		$this->fixed_kid_value = $kidValue;
        $this->api_v3_enabled = $this->fixed_k_value !== TamiPaymentClient::FIXED_K_VALUE;
	}

	private function generateKidValue(): string {
		$input = $this->secret_key . $this->fixed_kid_value;
		return base64_encode(hash('sha512', $input, true));
	}

	private function generateKValue(): string {
		$input = $this->secret_key . $this->fixed_k_value . $this->merchant_id . $this->terminal_id;
		return base64_encode(hash('sha512', $input, true));
	}

	private function getJWKResource(): JWKResource {
		$jwkResource = new JWKResource();
		$jwkResource->setKid($this->generateKidValue());
		$jwkResource->setK($this->generateKValue());
		return $jwkResource;
	}

	private static function base64UrlEncode(string $data): string {
		return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
	}

	public function generateJWKSignature($input): string {
        if(is_array($input) || is_object($input)) {
			$input = wp_json_encode($input);
		}
        if($this->api_v3_enabled) {
            return self::generateJWKSignatureV3(
                $this->fixed_kid_value, $this->fixed_k_value, $input
            );
        }

		$jwkResource = $this->getJWKResource();

		// Create header
		$header = [
			'kid' => $jwkResource->getKid(),
			'typ' => 'JWT',
			'alg' => 'HS512'
		];

		// Encode header and payload
		$headerEncoded = self::base64UrlEncode(wp_json_encode($header));
		$payloadEncoded = self::base64UrlEncode($input);

		// Create signature
		$dataToSign = $headerEncoded . '.' . $payloadEncoded;
		$signatureKey = base64_decode($jwkResource->getK());
		$signature = hash_hmac('sha512', $dataToSign, $signatureKey, true);
		$signatureEncoded = self::base64UrlEncode($signature);

		// Combine all parts
		return $headerEncoded . '.' . $payloadEncoded . '.' . $signatureEncoded;
	}
    private static function base64UrlDecode(string $data): string
    {
        $pad = 4 - (strlen($data) % 4);
        if ($pad < 4) $data .= str_repeat('=', $pad);
        return base64_decode(strtr($data, '-_', '+/'));
    }

    public static function generateJWKSignatureV3(string $kid, string $kBase64Url, string $bodyJson): string
    {
        // JWS header
        $header = [
            'alg' => 'HS512',
            'typ' => 'JWT',
            'kid' => $kid
        ];

        $headerJson   = json_encode($header, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        $headerB64    = self::base64UrlEncode($headerJson);

        $payloadB64   = self::base64UrlEncode($bodyJson);

        $signingInput = $headerB64 . '.' . $payloadB64;

        $keyBytes     = self::base64UrlDecode($kBase64Url);

        $signature    = hash_hmac('sha512', $signingInput, $keyBytes, true);
        $signatureB64 = self::base64UrlEncode($signature);

        return $headerB64 . '.' . $payloadB64 . '.' . $signatureB64;
    }

}