<?php

namespace App\Controllers;

use CodeIgniter\RESTful\ResourceController;
use App\Models\TransactionModel;

class Deposit extends ResourceController
{
    protected $db;

    public function __construct()
    {
        $this->db = \Config\Database::connect();
    }

    public function index()
    {
        // Get JSON input from request
        $json = $this->request->getJSON();

        if (!$json || !isset($json->msisdn) || !isset($json->amount)) {
            return $this->respond(['status' => 'error', 'message' => 'Invalid input data'], 400);
        }

        // API Endpoint
        $url = getenv('LIVE_SIGNATURE'); // Signature data
        $testUrl = getenv('TEST');  // Test
        $liveUrl = getenv('LIVE');  // Live

        // API Keys
        $merchantCode = getenv('MERCHANT_CODE');
        $consumerKey = getenv('CONSUMER_KEY');
        $consumerSecret = getenv('CONSUMER_SECRET');

        // Extract user data
        $msisdn = $json->msisdn;
        $amount = $json->amount;
        $transactionId = time() . rand(10000, 99999);
        $narration = "Deposit";

        // Generate signature
        $dataString = $url . "&" . $msisdn . "&" . $amount . "&" . $merchantCode . "&" . $transactionId . "&" . $narration;
        $authSignature = hash_hmac('sha256', $dataString, $consumerSecret);

        // Prepare payload
        $payload = [
            "msisdn" => $msisdn,
            "amount" => $amount,
            "merchantCode" => $merchantCode,
            "transactionId" => $transactionId,
            "consumerKey" => $consumerKey,
            "auth_signature" => $authSignature,
            "narration" => $narration
        ];

        // Send API request
        $client = \Config\Services::curlrequest();
        $response = $client->post($liveUrl, [
            "json" => $payload,
            "headers" => ["Content-Type" => "application/json"]
        ]);

        $responseData = json_decode($response->getBody(), true);

        // Save to database (PENDING status)
        $transactionModel = new TransactionModel();
        $transactionModel->insert([
            'transaction_id' => $transactionId,
            'reference'      => $responseData['transactionId'], // Reference from API
            'msisdn'         => $msisdn,
            'amount'         => $amount,
            'status'         => 'PENDING',
            'created_at'     => date('Y-m-d H:i:s')
        ]);

        // ✅ Automatically post to webhook after processing
        $this->postToWebhook([
            'transaction_id' => $transactionId,
            'reference'      => $responseData['transactionId'],
            'msisdn'         => $msisdn,
            'amount'         => $amount,
            'status'         => 'PENDING',
            'created_at'     => date('Y-m-d H:i:s')
        ]);

        return $this->respond($responseData, 200);
    }

    /**
     * ✅ Post Transaction Data to Webhook
     */
    private function postToWebhook($transaction)
    {
        // Connect to the database to fetch webhook URLs and their configurations
        $db = \Config\Database::connect();
        $query = $db->table('webhooks')->select('url, requires_plus')->get();
        $webhooks = $query->getResultArray();

        if (empty($webhooks)) {
            log_message('error', 'No webhooks found in the database.');
            return;
        }

        $client = \Config\Services::curlrequest();

        foreach ($webhooks as $webhook) {
            // Base URL from the database
            $url = trim($webhook['url']);

            // Ensure the URL does not have trailing slashes
            if (substr($url, -1) === '/') {
                $url = rtrim($url, '/');
            }

            // Conditionally append the transaction ID and "/+" if required
            if (!empty($webhook['requires_plus']) && $webhook['requires_plus'] == 1) {
                $transactionUrl = $url . '/' . $transaction['transaction_id'] . '/+';
            } else {
                $transactionUrl = $url;
            }

            try {
                // Send the data to the webhook with the transaction information
                $response = $client->post($transactionUrl, [
                    "json" => $transaction,
                    "headers" => ["Content-Type" => "application/json"],
                    "timeout" => 60, // Increase the timeout to avoid early failures
                ]);

                log_message('info', 'Webhook sent to: ' . $transactionUrl . ' | Response: ' . $response->getBody());
            } catch (\Exception $e) {
                log_message('error', 'Webhook failed for ' . $transactionUrl . ' | Error: ' . $e->getMessage());
            }
        }
    }

    public function Custom()
    {
        // Get JSON input from request
        $json = $this->request->getJSON();

        if (!$json || !isset($json->msisdn) || !isset($json->amount)) {
            return $this->respond(['status' => 'error', 'message' => 'Invalid input data'], 400);
        }

        // API Endpoint
        $url = getenv('LIVE_SIGNATURE'); // Signature data
        $testUrl = getenv('TEST');  // Test
        $liveUrl = getenv('LIVE');  // Live

        // API Keys
        $merchantCode = getenv('MERCHANT_CODE');
        $consumerKey = getenv('CONSUMER_KEY');
        $consumerSecret = getenv('CONSUMER_SECRET');

        // Extract user data
        $msisdn = $json->msisdn;
        $amount = $json->amount;
        $transactionId = $json->transactionId; // Custom transaction ID
        $narration = "Deposit";

        // Generate signature
        $dataString = $url . "&" . $msisdn . "&" . $amount . "&" . $merchantCode . "&" . $transactionId . "&" . $narration;
        $authSignature = hash_hmac('sha256', $dataString, $consumerSecret);

        // Prepare payload
        $payload = [
            "msisdn" => $msisdn,
            "amount" => $amount,
            "merchantCode" => $merchantCode,
            "transactionId" => $transactionId,
            "consumerKey" => $consumerKey,
            "auth_signature" => $authSignature,
            "narration" => $narration
        ];

        // Send API request
        $client = \Config\Services::curlrequest();
        $response = $client->post($liveUrl, [
            "json" => $payload,
            "headers" => ["Content-Type" => "application/json"]
        ]);

        $responseData = json_decode($response->getBody(), true);

        // Save to database (PENDING status)
        $transactionModel = new TransactionModel();
        $transactionModel->insert([
            'transaction_id' => $transactionId,
            'reference'      => $responseData['transactionId'], // Reference from API
            'msisdn'         => $msisdn,
            'amount'         => $amount,
            'status'         => 'PENDING',
            'created_at'     => date('Y-m-d H:i:s')
        ]);

        // ✅ Automatically post to webhook after processing
        $this->postToWebhook([
            'transaction_id' => $transactionId,
            'reference'      => $responseData['transactionId'],
            'msisdn'         => $msisdn,
            'amount'         => $amount,
            'status'         => 'PENDING',
            'created_at'     => date('Y-m-d H:i:s')
        ]);

        return $this->respond($responseData, 200);
    }

    public function callback()
    {
        // Get JSON input from Glitch
        $json = $this->request->getJSON(true); // true = associative array

        // Log the received JSON
        log_message('info', 'Callback JSON received from Glitch: ' . print_r($json, true));

        // Validate structure
        if (
            !isset($json['request']['transactionid'][0]) ||
            !isset($json['request']['method'][0]) ||
            !isset($json['request']['client_transaction'][0])
        ) {
            log_message('error', 'Invalid callback JSON structure.');
            return $this->respond(['status' => 'error', 'message' => 'Invalid callback data'], 400);
        }

        // Extract data
        $transactionId = is_array($json['request']['client_transaction']) ? $json['request']['client_transaction'][0] : $json['request']['client_transaction'];  // Your local transaction_id
        $method        = $json['request']['method'][0];

        // Determine transaction status
        if ($method === "receivePayment") {
            $status = "SUCCESS";
        } elseif ($method === "notifyFailedPayment") {
            $status = "FAILED";
        } else {
            log_message('error', 'Unknown method received: ' . $method);
            return $this->respond(['status' => 'error', 'message' => 'Unknown method'], 400);
        }

        // Update transaction in DB
        $transactionModel = new TransactionModel();
        $updateResult = $transactionModel->where('transaction_id', $transactionId)
            ->set(['status' => $status])
            ->update();

        if ($updateResult) {
            log_message('info', "Transaction ID: $transactionId updated to status: $status");
        } else {
            log_message('error', "Failed to update transaction ID: $transactionId");
        }

        // Respond to Glitch (no need to send XML)
        return $this->respond(['status' => 'success', 'message' => 'Transaction processed'], 200);
    }

    // Function to get transaction status by ID
    public function getTransactionStatus($transactionId)
    {
        $db = \Config\Database::connect();
        $query = $db->table('transactions')->where('transaction_id', $transactionId)->get();
        $transaction = $query->getRowArray();

        if (!$transaction) {
            return $this->respond(['status' => 'error', 'message' => 'Transaction not found'], 404);
        }

        return $this->respond(['status' => 'success', 'transaction' => $transaction]);
    }

    public function getIp()
    {
        $host = gethostname();
        $ip = gethostbyname($host);

        return $this->response->setJSON(['ip' => $ip]);
    }
}
