<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class FiuuCloudEcrService
{
    protected string $baseUrl;
    protected string $posId;
    protected string $password;
    protected string $merchantId;
    protected string $deviceId;
    protected string $secretKey;
    protected string $apiVersion;
    protected ?string $accessToken = null;
    protected ?string $refreshToken = null;

    public function __construct()
    {
        $this->baseUrl = config('fiuu.base_url');
        $this->posId = config('fiuu.pos_id');
        $this->password = config('fiuu.password');
        $this->merchantId = config('fiuu.merchant_id');
        $this->deviceId = config('fiuu.device_id');
        $this->secretKey = config('fiuu.secret_key');
        $this->apiVersion = config('fiuu.api_version', 'v1');
    }

    /**
     * Authenticate and get access token
     */
    public function authenticate(): array
    {
        $response = Http::post("{$this->baseUrl}/auth/login", [
            'posId' => $this->posId,
            'password' => $this->password,
        ]);
        if ($response->successful()) {
            $data = $response->json();
            $this->accessToken = $data['access']['token'] ?? null;
            $this->refreshToken = $data['refresh']['token'] ?? null;
            return [
                'success' => true,
                'data' => $data,
            ];
        }

        return [
            'success' => false,
            'error' => $response->json() ?? $response->body(),
            'status' => $response->status(),
        ];
    }

    /**
     * Refresh access token
     */
    public function refreshAccessToken(): array
    {
        if (!$this->refreshToken) {
            return ['success' => false, 'error' => 'No refresh token available'];
        }

        $response = Http::withToken($this->refreshToken)
            ->post("{$this->baseUrl}/auth/refresh");

        if ($response->successful()) {
            $data = $response->json();
            $this->accessToken = $data['access']['token'] ?? null;
            $this->refreshToken = $data['refresh']['token'] ?? null;
            return [
                'success' => true,
                'data' => $data,
            ];
        }

        return [
            'success' => false,
            'error' => $response->json() ?? $response->body(),
            'status' => $response->status(),
        ];
    }

    /**
     * Set access token manually (e.g., from session)
     */
    public function setAccessToken(string $token): self
    {
        $this->accessToken = $token;
        return $this;
    }

    /**
     * Set refresh token manually
     */
    public function setRefreshToken(string $token): self
    {
        $this->refreshToken = $token;
        return $this;
    }

    /**
     * Get list of terminals
     */
    public function getTerminals(): array
    {
        return $this->makeAuthenticatedRequest('GET', '/api/terminals');
    }

    /**
     * Get e-wallet channels
     */
    public function getEwalletChannels(string $currency = 'MYR'): array
    {
        return $this->makeAuthenticatedRequest('GET', "/api/ewallet-channels?currency={$currency}");
    }

    /**
     * Initiate a Sale transaction
     */
    public function sale(
        string $amount,
        string $paymentMethod,
        ?string $paymentChannel = null,
        ?string $referenceLabel = null,
        ?string $note = null,
        ?int $printCount = 2
    ): array {
        $referenceId = $this->generateReferenceId();
        $datetime = $this->getCurrentDatetime();

        $payload = [
            'transType' => 'sale',
            'posId' => $this->posId,
            'merchantId' => $this->merchantId,
            'deviceId' => $this->deviceId,
            'referenceId' => $referenceId,
            'apiVersion' => $this->apiVersion,
            'datetime' => $datetime,
            'transData' => [
                'transAmt' => number_format((float) $amount, 2, '.', ''),
                'paymentMethod' => $paymentMethod,
            ],
        ];

        // Add optional fields
        if ($referenceLabel) {
            $payload['referenceLabel'] = $referenceLabel;
        }

        if ($paymentChannel && $paymentMethod === 'qrCustScan') {
            $payload['transData']['paymentChannel'] = $paymentChannel;
        }

        if ($note) {
            $payload['transData']['note'] = $note;
        }

        if ($printCount !== null) {
            $payload['transData']['printCount'] = $printCount;
        }

        // Generate signature
        $payload['signature'] = $this->generateSignature($payload);

        Log::info('Fiuu Sale Request', ['payload' => $payload]);

        return $this->makeAuthenticatedRequest('POST', '/api/transfer', $payload);
    }

    /**
     * Initiate a Void transaction
     */
    public function void(string $transId, ?string $invNo = null): array
    {
        $referenceId = $this->generateReferenceId();
        $datetime = $this->getCurrentDatetime();

        $payload = [
            'transType' => 'void',
            'posId' => $this->posId,
            'merchantId' => $this->merchantId,
            'deviceId' => $this->deviceId,
            'referenceId' => $referenceId,
            'apiVersion' => $this->apiVersion,
            'datetime' => $datetime,
            'transData' => [
                'transId' => $transId,
            ],
        ];

        if ($invNo) {
            $payload['transData']['invNo'] = $invNo;
        }

        $payload['signature'] = $this->generateSignature($payload);

        Log::info('Fiuu Void Request', ['payload' => $payload]);

        return $this->makeAuthenticatedRequest('POST', '/api/transfer', $payload);
    }

    /**
     * Get last transaction
     */
    public function getLast(): array
    {
        $referenceId = $this->generateReferenceId();
        $datetime = $this->getCurrentDatetime();

        $payload = [
            'transType' => 'getLast',
            'posId' => $this->posId,
            'merchantId' => $this->merchantId,
            'deviceId' => $this->deviceId,
            'referenceId' => $referenceId,
            'apiVersion' => $this->apiVersion,
            'datetime' => $datetime,
        ];

        $payload['signature'] = $this->generateSignature($payload);

        return $this->makeAuthenticatedRequest('POST', '/api/transfer', $payload);
    }

    /**
     * Wallet inquiry for pending transactions
     */
    public function walletInquiry(string $originalDatetime): array
    {
        $referenceId = $this->generateReferenceId();
        $datetime = $this->getCurrentDatetime();

        $payload = [
            'transType' => 'walletInquiry',
            'posId' => $this->posId,
            'merchantId' => $this->merchantId,
            'deviceId' => $this->deviceId,
            'referenceId' => $referenceId,
            'apiVersion' => $this->apiVersion,
            'datetime' => $datetime,
            'transData' => [
                'originalDatetime' => $originalDatetime,
            ],
        ];

        $payload['signature'] = $this->generateSignature($payload);

        return $this->makeAuthenticatedRequest('POST', '/api/transfer', $payload);
    }

    /**
     * Generate HMAC-SHA256 signature for payload
     */
    public function generateSignature(array $payload): string
    {
        // Remove signature field if exists
        unset($payload['signature']);

        // Flatten the payload
        $values = $this->flattenArray($payload);

        // Sort alphabetically
        sort($values, SORT_STRING);

        // Concatenate all values
        $concatenated = implode('', $values);

        // Generate HMAC-SHA256 hash
        return hash_hmac('sha256', $concatenated, $this->secretKey);
    }

    /**
     * Verify response signature
     */
    public function verifySignature(array $response): bool
    {
        if (!isset($response['signature'])) {
            return false;
        }

        $receivedSignature = $response['signature'];
        $calculatedSignature = $this->generateSignature($response);

        return hash_equals($calculatedSignature, $receivedSignature);
    }

    /**
     * Flatten array recursively to extract all values
     */
    protected function flattenArray(array $array): array
    {
        $result = [];

        foreach ($array as $value) {
            if (is_array($value)) {
                $result = array_merge($result, $this->flattenArray($value));
            } elseif ($value !== null && $value !== '') {
                $result[] = (string) $value;
            }
        }

        return $result;
    }

    /**
     * Generate unique reference ID
     */
    protected function generateReferenceId(): string
    {
        return 'POS' . strtoupper(base_convert(time(), 10, 36)) . strtoupper(substr(uniqid(), -4));
    }

    /**
     * Get current datetime in required format (YYYYMMDDTHHMMSS)
     */
    protected function getCurrentDatetime(): string
    {
        return gmdate('YmdHis');
    }

    /**
     * Make authenticated API request
     */
    protected function makeAuthenticatedRequest(string $method, string $endpoint, array $data = []): array
    {
        if (!$this->accessToken) {
            return ['success' => false, 'error' => 'Not authenticated. Please login first.'];
        }

        $url = $this->baseUrl . $endpoint;

        try {
            $request = Http::withToken($this->accessToken)
                ->timeout(120); // ECR transactions may take time

            if ($method === 'GET') {
                $response = $request->get($url);
            } else {
                $response = $request->post($url, $data);
            }
			
            $responseData = $response->json() ?? [];
			$responseData['posId'] = $this->posId ;
			$responseData['password'] = $this->password ;
			$responseData['merchantId'] = $this->merchantId ;
			$responseData['deviceId'] = $this->deviceId ;
			$responseData['secretKey'] = $this->secretKey ;
            Log::info('Fiuu API Response', [
                'endpoint' => $endpoint,
                'status' => $response->status(),
                'response' => $responseData,
            ]);

            if ($response->successful()) {
                return [
                    'success' => true,
                    'data' => $responseData,
                ];
            }

            return [
                'success' => false,
                'error' => $responseData,
                'status' => $response->status(),
            ];
        } catch (\Exception $e) {
            Log::error('Fiuu API Error', [
                'endpoint' => $endpoint,
                'error' => $e->getMessage(),
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage(),
            ];
        }
    }

    // Getters for configuration values
    public function getPosId(): string
    {
        return $this->posId;
    }

    public function getMerchantId(): string
    {
        return $this->merchantId;
    }

    public function getDeviceId(): string
    {
        return $this->deviceId;
    }
}