<?php

namespace Services;

use Libs\BashExecutor;
use Models\PaymentModel;

class PaymentService
{
    private const DEFAULT_EXPIRES = 1800;
    private const DEFAULT_STATUS_ID = PaymentModel::STATUS_PENDING;

    private PaymentModel $paymentModel;
    private string $wooviCliPath;

    public function __construct(?string $wooviCliPath = null)
    {
        $this->paymentModel = new PaymentModel();
        $this->wooviCliPath = $wooviCliPath ?? $this->resolveWooviCliPath();
    }

    public function initiatePayment(int $value, ?string $paymentFlag = null): array
    {
        if ($value <= 0) {
            throw new \InvalidArgumentException('Payment value must be greater than zero');
        }

        $userId = $this->resolveAuthenticatedUserId();
        $externalId = $this->generateExternalId();
        $pixCode = $this->runWooviCommand($value, self::DEFAULT_EXPIRES, $externalId);

        $paymentId = $this->paymentModel->create(
            $externalId,
            self::DEFAULT_STATUS_ID,
            $userId,
            null,
            '',
            $paymentFlag ?? ''
        );

        return [
            'payment_id' => $paymentId,
            'payment_code' => $pixCode,
            'payment_external_id' => $externalId,
        ];
    }

    private function resolveAuthenticatedUserId(): int
    {
        $userId = $GLOBALS['api_user_id'] ?? null;
        if (!is_numeric($userId) || (int)$userId <= 0) {
            throw new \RuntimeException('Authenticated user context not available for payment creation');
        }

        return (int)$userId;
    }

    private function generateExternalId(): string
    {
        return 'PAY_' . bin2hex(random_bytes(8));
    }

    private function resolveWooviCliPath(): string
    {
        if (!empty($_ENV['WOOVI_CLI_PATH'])) {
            return $_ENV['WOOVI_CLI_PATH'];
        }

        return dirname(__DIR__, 2) . '/cli-woovi/woovi';
    }

    private function runWooviCommand(int $value, int $expires, string $externalId): string
    {
        $cliPath = $this->wooviCliPath;
        if (!is_file($cliPath)) {
            throw new \RuntimeException('Woovi CLI executable not found at ' . $cliPath);
        }
        if (!is_executable($cliPath)) {
            throw new \RuntimeException('Woovi CLI executable is not executable at ' . $cliPath);
        }

        $command = sprintf(
            '%s -value=%d -expires=%d -correlation=%s',
            escapeshellarg($cliPath),
            $value,
            $expires,
            escapeshellarg($externalId)
        );

        $result = BashExecutor::run($command, 60);
        if (($result['exitCode'] ?? 1) !== 0) {
            $message = $result['error'] ?: $result['output'] ?: 'Unknown Woovi CLI error';
            throw new \RuntimeException('Woovi CLI failed: ' . $message);
        }

        $output = trim((string)($result['output'] ?? ''));
        if ($output === '') {
            $error = trim((string)($result['error'] ?? ''));
            $combined = $error !== '' ? $error : 'empty response';
            throw new \RuntimeException('Woovi CLI did not return a payment code: ' . $combined);
        }

        return $output;
    }
}
