<?php

namespace App\Controllers;

use CodeIgniter\RESTful\ResourceController;
use App\Libraries\CardyfieService;

class Cardyfie extends ResourceController
{
    protected $cardyfieService;

    public function __construct()
    {
        $this->cardyfieService = new CardyfieService();
    }

    /**
     * Create a customer in Cardyfie
     * POST /api/cardyfie/customer/create
     * 
     * Simplified endpoint - only requires essential fields
     */
    public function createCustomer()
    {
        $json = $this->request->getJSON();

        if (!$json) {
            return $this->respond([
                'success' => false,
                'message' => 'Invalid JSON data'
            ], 400);
        }

        // Validate required fields
        $requiredFields = ['first_name', 'last_name', 'email', 'date_of_birth', 'id_type', 'id_number', 'id_front_image', 'user_image', 'house_number', 'address_line_1', 'city', 'zip_code', 'country'];
        foreach ($requiredFields as $field) {
            if (!isset($json->$field) || empty($json->$field)) {
                return $this->respond([
                    'success' => false,
                    'message' => "Missing required field: {$field}"
                ], 400);
            }
        }

        // Prepare customer data
        $customerData = [
            'first_name' => $json->first_name,
            'last_name' => $json->last_name,
            'email' => $json->email,
            'date_of_birth' => $json->date_of_birth,
            'id_type' => $json->id_type,
            'id_number' => $json->id_number,
            'id_front_image' => $json->id_front_image,
            'user_image' => $json->user_image,
            'house_number' => $json->house_number,
            'address_line_1' => $json->address_line_1,
            'city' => $json->city,
            'zip_code' => $json->zip_code,
            'country' => $json->country
        ];

        // Optional fields
        if (isset($json->id_back_image) && !empty($json->id_back_image)) {
            $customerData['id_back_image'] = $json->id_back_image;
        }

        if (isset($json->state) && !empty($json->state)) {
            $customerData['state'] = $json->state;
        }

        if (isset($json->reference_id) && !empty($json->reference_id)) {
            $customerData['reference_id'] = $json->reference_id;
        }

        if (isset($json->user_id) && !empty($json->user_id)) {
            $customerData['user_id'] = $json->user_id;
        }

        // Create customer
        $result = $this->cardyfieService->createCustomer($customerData);

        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Get customer by ULID
     * GET /api/cardyfie/customer/get/{ulid}
     * 
     * Cardyfie API requires ULID as a path parameter
     */
    public function getCustomer($ulid = null)
    {
        // Get ULID from path parameter or query parameter (for flexibility)
        if (!$ulid) {
            $ulid = $this->request->getGet('ulid');
        }

        if (!$ulid) {
            return $this->respond([
                'success' => false,
                'message' => 'Customer ULID is required'
            ], 400);
        }

        $result = $this->cardyfieService->getCustomer($ulid);

        return $this->respond($result, $result['success'] ? 200 : 404);
    }

    /**
     * Update customer in Cardyfie
     * PUT /api/cardyfie/customer/update/{ulid}
     * 
     * Note: Email is not included in update (unlike create)
     * Image fields can be omitted to keep existing images
     */
    public function updateCustomer($ulid = null)
    {
        // Get ULID from path parameter or request body
        if (!$ulid) {
            $json = $this->request->getJSON();
            if ($json && isset($json->ulid)) {
                $ulid = $json->ulid;
            }
        }

        if (!$ulid) {
            return $this->respond([
                'success' => false,
                'message' => 'Customer ULID is required'
            ], 400);
        }

        $json = $this->request->getJSON();

        if (!$json) {
            return $this->respond([
                'success' => false,
                'message' => 'Invalid JSON data'
            ], 400);
        }

        // Validate required fields (email is NOT required for update)
        $requiredFields = ['first_name', 'last_name', 'date_of_birth', 'id_type', 'id_number', 'id_front_image', 'user_image', 'house_number', 'address_line_1', 'city', 'zip_code'];
        foreach ($requiredFields as $field) {
            if (!isset($json->$field) || empty($json->$field)) {
                return $this->respond([
                    'success' => false,
                    'message' => "Missing required field: {$field}"
                ], 400);
            }
        }

        // Prepare customer data
        $customerData = [
            'first_name' => $json->first_name,
            'last_name' => $json->last_name,
            'date_of_birth' => $json->date_of_birth,
            'id_type' => $json->id_type,
            'id_number' => $json->id_number,
            'id_front_image' => $json->id_front_image,
            'user_image' => $json->user_image,
            'house_number' => $json->house_number,
            'address_line_1' => $json->address_line_1,
            'city' => $json->city,
            'zip_code' => $json->zip_code
        ];

        // Optional fields
        if (isset($json->id_back_image) && !empty($json->id_back_image)) {
            $customerData['id_back_image'] = $json->id_back_image;
        }

        if (isset($json->state) && !empty($json->state)) {
            $customerData['state'] = $json->state;
        }

        // Meta data - can be object or individual fields
        if (isset($json->meta) && is_object($json->meta)) {
            $customerData['meta'] = (array) $json->meta;
        } elseif (isset($json->user_id) && !empty($json->user_id)) {
            $customerData['user_id'] = $json->user_id;
        }

        // Update customer
        $result = $this->cardyfieService->updateCustomer($ulid, $customerData);

        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Get available card currencies
     * GET /api/cardyfie/card/currencies
     * 
     * Returns list of currencies available for card issuance
     */
    public function getCardCurrencies()
    {
        $result = $this->cardyfieService->getCardCurrencies();
        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Issue a card for a customer
     * POST /api/cardyfie/card/issue
     * 
     * Creates a virtual card for the specified customer
     */
    public function issueCard()
    {
        $json = $this->request->getJSON();

        if (!$json) {
            return $this->respond([
                'success' => false,
                'message' => 'Invalid JSON data'
            ], 400);
        }

        // Validate required fields
        $requiredFields = ['customer_ulid', 'card_name', 'card_currency', 'card_type', 'card_provider'];
        foreach ($requiredFields as $field) {
            if (!isset($json->$field) || empty($json->$field)) {
                return $this->respond([
                    'success' => false,
                    'message' => "Missing required field: {$field}"
                ], 400);
            }
        }

        // Prepare card data
        $cardData = [
            'customer_ulid' => $json->customer_ulid,
            'card_name' => $json->card_name,
            'card_currency' => $json->card_currency,
            'card_type' => $json->card_type,
            'card_provider' => $json->card_provider
        ];

        // Optional reference_id
        if (isset($json->reference_id) && !empty($json->reference_id)) {
            $cardData['reference_id'] = $json->reference_id;
        } elseif (isset($json->meta) && is_object($json->meta) && isset($json->meta->reference_id)) {
            $cardData['meta'] = ['reference_id' => $json->meta->reference_id];
        }

        // Issue card
        $result = $this->cardyfieService->issueCard($cardData);

        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Get all cards
     * GET /api/cardyfie/card/get-all
     * 
     * Returns paginated list of all cards
     * Supports optional pagination: ?page=1&per_page=10
     */
    public function getCards()
    {
        // Get pagination parameters from query string
        $page = (int) ($this->request->getGet('page') ?? 1);
        $perPage = (int) ($this->request->getGet('per_page') ?? 10);

        // Validate pagination parameters
        if ($page < 1) {
            $page = 1;
        }
        if ($perPage < 1 || $perPage > 100) {
            $perPage = 10; // Default to 10, max 100
        }

        $result = $this->cardyfieService->getCards($page, $perPage);
        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Get card details by ULID
     * GET /api/cardyfie/card/details/{ulid}
     * 
     * Returns detailed information about a specific card including sensitive data (CVV, real PAN)
     */
    public function getCardDetails($cardUlid = null)
    {
        // Get ULID from path parameter or query parameter (for flexibility)
        if (!$cardUlid) {
            $cardUlid = $this->request->getGet('ulid');
        }

        if (!$cardUlid) {
            return $this->respond([
                'success' => false,
                'message' => 'Card ULID is required'
            ], 400);
        }

        $result = $this->cardyfieService->getCardDetails($cardUlid);
        return $this->respond($result, $result['success'] ? 200 : 404);
    }

    /**
     * Deposit funds to a card
     * POST /api/cardyfie/card/deposit/{ulid}
     * 
     * Adds funds to a card balance
     */
    public function depositToCard($cardUlid = null)
    {
        // Get ULID from path parameter or request body
        if (!$cardUlid) {
            $json = $this->request->getJSON();
            if ($json && isset($json->ulid)) {
                $cardUlid = $json->ulid;
            }
        }

        if (!$cardUlid) {
            return $this->respond([
                'success' => false,
                'message' => 'Card ULID is required'
            ], 400);
        }

        $json = $this->request->getJSON();

        if (!$json) {
            return $this->respond([
                'success' => false,
                'message' => 'Invalid JSON data'
            ], 400);
        }

        // Validate required fields
        if (!isset($json->amount) || empty($json->amount)) {
            return $this->respond([
                'success' => false,
                'message' => 'Amount is required'
            ], 400);
        }

        // Validate amount
        if (!is_numeric($json->amount) || $json->amount <= 0) {
            return $this->respond([
                'success' => false,
                'message' => 'Amount must be a positive number'
            ], 400);
        }

        // Deposit to card
        $result = $this->cardyfieService->depositToCard($cardUlid, (float) $json->amount);

        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Withdraw funds from a card
     * POST /api/cardyfie/card/withdraw/{ulid}
     * 
     * Removes funds from a card balance
     */
    public function withdrawFromCard($cardUlid = null)
    {
        // Get ULID from path parameter or request body
        if (!$cardUlid) {
            $json = $this->request->getJSON();
            if ($json && isset($json->ulid)) {
                $cardUlid = $json->ulid;
            }
        }

        if (!$cardUlid) {
            return $this->respond([
                'success' => false,
                'message' => 'Card ULID is required'
            ], 400);
        }

        $json = $this->request->getJSON();

        if (!$json) {
            return $this->respond([
                'success' => false,
                'message' => 'Invalid JSON data'
            ], 400);
        }

        // Validate required fields
        if (!isset($json->amount) || empty($json->amount)) {
            return $this->respond([
                'success' => false,
                'message' => 'Amount is required'
            ], 400);
        }

        // Validate amount
        if (!is_numeric($json->amount) || $json->amount <= 0) {
            return $this->respond([
                'success' => false,
                'message' => 'Amount must be a positive number'
            ], 400);
        }

        // Withdraw from card
        $result = $this->cardyfieService->withdrawFromCard($cardUlid, (float) $json->amount);

        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Get card transactions
     * GET /api/cardyfie/card/transactions
     * 
     * Returns transactions for a specific card or all cards
     * Supports optional query parameter: ?card_ulid={ulid}
     */
    public function getCardTransactions()
    {
        // Get card_ulid from query parameter (optional)
        $cardUlid = $this->request->getGet('card_ulid');
        
        // If empty string, convert to null
        if ($cardUlid === '') {
            $cardUlid = null;
        }

        $result = $this->cardyfieService->getCardTransactions($cardUlid);
        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Freeze a card
     * POST /api/cardyfie/card/freeze/{ulid}
     * 
     * Freezes a card, preventing it from being used for transactions
     */
    public function freezeCard($cardUlid = null)
    {
        // Get ULID from path parameter or request body
        if (!$cardUlid) {
            $json = $this->request->getJSON();
            if ($json && isset($json->ulid)) {
                $cardUlid = $json->ulid;
            }
        }

        if (!$cardUlid) {
            return $this->respond([
                'success' => false,
                'message' => 'Card ULID is required'
            ], 400);
        }

        // Freeze card (no body required, just ULID)
        $result = $this->cardyfieService->freezeCard($cardUlid);

        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Unfreeze a card
     * POST /api/cardyfie/card/unfreeze/{ulid}
     * 
     * Unfreezes a card, allowing it to be used for transactions again
     */
    public function unfreezeCard($cardUlid = null)
    {
        // Get ULID from path parameter or request body
        if (!$cardUlid) {
            $json = $this->request->getJSON();
            if ($json && isset($json->ulid)) {
                $cardUlid = $json->ulid;
            }
        }

        if (!$cardUlid) {
            return $this->respond([
                'success' => false,
                'message' => 'Card ULID is required'
            ], 400);
        }

        // Unfreeze card (no body required, just ULID)
        $result = $this->cardyfieService->unfreezeCard($cardUlid);

        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Close a card
     * POST /api/cardyfie/card/close/{ulid}
     * 
     * Permanently closes a card. This action is irreversible.
     */
    public function closeCard($cardUlid = null)
    {
        // Get ULID from path parameter or request body
        if (!$cardUlid) {
            $json = $this->request->getJSON();
            if ($json && isset($json->ulid)) {
                $cardUlid = $json->ulid;
            }
        }

        if (!$cardUlid) {
            return $this->respond([
                'success' => false,
                'message' => 'Card ULID is required'
            ], 400);
        }

        // Close card (no body required, just ULID)
        $result = $this->cardyfieService->closeCard($cardUlid);

        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * Webhook endpoint for receiving Cardyfie events
     * POST /api/cardyfie/webhook
     * 
     * Receives webhooks from Cardyfie and processes them
     */
    public function webhook()
    {
        try {
            // Get raw request body for signature verification
            $rawBody = $this->request->getBody();
            $payload = $this->request->getJSON(true);
            
            if (!$payload) {
                log_message('error', 'Cardyfie Webhook: Invalid JSON payload');
                return $this->respond([
                    'success' => false,
                    'message' => 'Invalid JSON payload'
                ], 400);
            }
            
            // Verify webhook signature (optional but recommended)
            $signature = $this->request->getHeaderLine('x-webhook-signature');
            $webhookSecret = $_ENV['cardyfie.webhook_secret'] ?? '';
            
            if (!empty($webhookSecret) && !empty($signature)) {
                if (!$this->verifyWebhookSignature($payload, $signature, $webhookSecret)) {
                    log_message('error', 'Cardyfie Webhook: Invalid signature');
                    return $this->respond([
                        'success' => false,
                        'message' => 'Invalid webhook signature'
                    ], 401);
                }
            }
            
            // Extract event information
            $eventId = $payload['event']['id'] ?? null;
            $eventType = $payload['event']['type'] ?? 'unknown';
            $eventData = $payload['data'] ?? [];
            
            // Log webhook receipt
            log_message('info', "Cardyfie Webhook received: {$eventType} | Event ID: {$eventId}");
            
            // Process webhook based on event type
            $this->processWebhookEvent($eventType, $eventData, $payload);
            
            // Forward to configured webhook URLs if any
            $this->forwardWebhook($payload);
            
            // Always return 200 OK to acknowledge receipt
            return $this->respond([
                'success' => true,
                'message' => 'Webhook received and processed',
                'event_type' => $eventType,
                'event_id' => $eventId
            ], 200);
            
        } catch (\Exception $e) {
            log_message('error', 'Cardyfie Webhook Error: ' . $e->getMessage());
            // Still return 200 to prevent Cardyfie from retrying
            return $this->respond([
                'success' => false,
                'message' => 'Webhook processing error',
                'error' => $e->getMessage()
            ], 200);
        }
    }
    
    /**
     * Verify webhook signature using HMAC SHA256
     */
    private function verifyWebhookSignature($payload, $receivedSignature, $secret): bool
    {
        $expectedSignature = hash_hmac('sha256', json_encode($payload), $secret);
        return hash_equals($expectedSignature, $receivedSignature);
    }
    
    /**
     * Process webhook event based on type
     */
    private function processWebhookEvent($eventType, $eventData, $fullPayload)
    {
        switch ($eventType) {
            case 'customer.create':
                $this->handleCustomerCreated($eventData);
                break;
            case 'card.issued':
                $this->handleCardIssued($eventData);
                break;
            default:
                log_message('info', "Cardyfie Webhook: Unhandled event type: {$eventType}");
        }
    }
    
    /**
     * Handle customer.created webhook event
     */
    private function handleCustomerCreated($customerData)
    {
        $ulid = $customerData['ulid'] ?? null;
        $status = $customerData['status'] ?? 'UNKNOWN';
        
        log_message('info', "Cardyfie Customer Created: ULID={$ulid}, Status={$status}");
        
        // Here you can:
        // - Update your database
        // - Send notifications
        // - Trigger other business logic
    }
    
    /**
     * Handle card.issued webhook event
     */
    private function handleCardIssued($cardData)
    {
        $ulid = $cardData['ulid'] ?? null;
        $cardName = $cardData['card_name'] ?? 'N/A';
        $status = $cardData['status'] ?? 'UNKNOWN';
        
        log_message('info', "Cardyfie Card Issued: ULID={$ulid}, Name={$cardName}, Status={$status}");
        
        // Here you can:
        // - Update your database
        // - Send notifications to user
        // - Trigger other business logic
    }
    
    /**
     * Forward webhook to configured webhook URLs
     */
    private function forwardWebhook($payload)
    {
        $webhookUrls = $_ENV['cardyfie.webhook_urls'] ?? '';
        
        if (empty($webhookUrls)) {
            return;
        }
        
        // Support multiple webhook URLs (comma-separated)
        $urls = array_map('trim', explode(',', $webhookUrls));
        
        foreach ($urls as $url) {
            if (empty($url)) {
                continue;
            }
            
            try {
                $client = \Config\Services::curlrequest();
                $response = $client->post($url, [
                    'json' => $payload,
                    'headers' => [
                        'Content-Type' => 'application/json',
                        'User-Agent' => 'Cardyfie-Webhook-Forwarder/1.0'
                    ],
                    'timeout' => 10,
                    'http_errors' => false
                ]);
                
                $statusCode = $response->getStatusCode();
                if ($statusCode >= 200 && $statusCode < 300) {
                    log_message('info', "Cardyfie webhook forwarded to: {$url} | Status: {$statusCode}");
                } else {
                    log_message('warning', "Cardyfie webhook forward failed to: {$url} | Status: {$statusCode}");
                }
            } catch (\Exception $e) {
                log_message('error', "Cardyfie webhook forward error for {$url}: " . $e->getMessage());
            }
        }
    }

    /**
     * Health check endpoint
     * GET /api/cardyfie/health
     */
    public function health()
    {
        return $this->respond([
            'success' => true,
            'message' => 'Cardyfie service is running',
            'environment' => $this->cardyfieService->getEnvironment(),
            'timestamp' => date('Y-m-d H:i:s')
        ]);
    }
}

