<?php
/**
 * ================================================================
 * DOJAH KYC CLASS
 * ================================================================
 * File: app/Core/DojahKYC.php
 *
 * Handles the server-side of the Dojah Web SDK verification flow:
 *
 *  1. Page renders a <dojah-button widgetId="..."> web component.
 *     Dojah loads its own popup — no JS needed on our side.
 *  2. User completes verification inside the Dojah popup.
 *  3. Dojah redirects to kyc-callback.php?verification_id=xxx
 *     (the callback URL is set in your Dojah dashboard per widget)
 *  4. kyc-callback.php calls processCallback() which:
 *       - Calls Dojah API to fetch the full verified result
 *       - Saves everything to kyc_verifications table
 *       - Updates customers / vendors table
 *       - Locks name fields
 *
 * .env variables used (loaded automatically by config.php):
 *   DOJAH_SECRET_KEY              — server-side secret key (PHP only)
 *   DOJAH_ENV                     — 'sandbox' | 'live'
 *   DOJAH_WIDGET_CUSTOMER_IDENTITY — Widget ID for customer identity widget
 *   DOJAH_WIDGET_VENDOR_PERSONAL   — Widget ID for vendor personal widget
 *   DOJAH_WIDGET_VENDOR_BUSINESS   — Widget ID for vendor business widget
 *
 * config.php computes:
 *   DOJAH_BASE_URL  — API base URL (switches sandbox/live automatically)
 *   KYC_CALLBACK_URL — full URL to kyc-callback.php
 * ================================================================
 */

class DojahKYC {

    const TYPE_CUSTOMER_IDENTITY = 'customer_identity';
    const TYPE_VENDOR_PERSONAL   = 'vendor_personal';
    const TYPE_VENDOR_BUSINESS   = 'vendor_business';

    private string $secret_key;
    private string $base_url;
    private $db;

    public function __construct() {
        $this->secret_key = DOJAH_SECRET_KEY;
        $this->base_url   = DOJAH_BASE_URL;
        $this->db         = Database::getInstance();
    }

    // ================================================================
    // PUBLIC: GET WIDGET ID FOR A VERIFICATION TYPE
    // Used by pages to set the widgetId attribute on <dojah-button>
    // ================================================================

    public function getWidgetId(string $verification_type): string {
        switch ($verification_type) {
            case self::TYPE_CUSTOMER_IDENTITY:
                return DOJAH_WIDGET_CUSTOMER_IDENTITY;
            case self::TYPE_VENDOR_PERSONAL:
                return DOJAH_WIDGET_VENDOR_PERSONAL;
            case self::TYPE_VENDOR_BUSINESS:
                return DOJAH_WIDGET_VENDOR_BUSINESS;
            default:
                return '';
        }
    }

    // ================================================================
    // PUBLIC: PROCESS CALLBACK
    // Called from kyc-callback.php after Dojah redirects back.
    // ================================================================

    /**
     * Fetch the verification result from Dojah and persist it.
     *
     * @param int    $user_id           users.id
     * @param string $verification_id   ?verification_id from Dojah redirect
     * @param string $verification_type 'customer_identity'|'vendor_personal'|'vendor_business'
     * @return array ['success' => bool, 'message' => string, 'data' => array|null]
     */
    public function processCallback(
        int    $user_id,
        string $verification_id,
        string $verification_type
    ): array {
        $allowed = [
            self::TYPE_CUSTOMER_IDENTITY,
            self::TYPE_VENDOR_PERSONAL,
            self::TYPE_VENDOR_BUSINESS,
        ];

        if (!in_array($verification_type, $allowed, true)) {
            return ['success' => false, 'message' => 'Invalid verification type.', 'data' => null];
        }

        // Already verified for this type — skip
        if ($this->isTypeVerified($user_id, $verification_type)) {
            return ['success' => false, 'message' => 'Already verified.', 'data' => null];
        }

        // Fetch result from Dojah
        $api_result = $this->fetchVerificationResult($verification_id, $verification_type);

        $user_type = ($verification_type === self::TYPE_CUSTOMER_IDENTITY) ? 'customer' : 'vendor';

        if (!$api_result['success']) {
            $this->saveRecord(
                $user_id, $user_type, $verification_type,
                $verification_id, 'failed', [], $api_result['raw'], $api_result['message']
            );
            return ['success' => false, 'message' => $api_result['message'], 'data' => null];
        }

        $data = $api_result['data'];

        // Save to DB
        $this->saveRecord(
            $user_id, $user_type, $verification_type,
            $verification_id, 'verified', $data, $api_result['raw']
        );

        // Update customer/vendor table
        switch ($verification_type) {
            case self::TYPE_CUSTOMER_IDENTITY:
                $this->updateCustomerAfterVerification($user_id, $data);
                break;
            case self::TYPE_VENDOR_PERSONAL:
                $this->updateVendorAfterPersonalVerification($user_id, $data);
                break;
            case self::TYPE_VENDOR_BUSINESS:
                $this->updateVendorAfterBusinessVerification($user_id, $data);
                break;
        }

        return [
            'success' => true,
            'message' => 'Verification completed successfully.',
            'data'    => $data,
        ];
    }

    // ================================================================
    // PRIVATE: FETCH RESULT FROM DOJAH API
    // ================================================================

    private function fetchVerificationResult(string $verification_id, string $type): array {
        // Business (Document Verification) uses a different endpoint
        $endpoint = ($type === self::TYPE_VENDOR_BUSINESS)
            ? '/api/v1/kyc/document/verification'
            : '/api/v1/kyc/govdata/verification';

        $response = $this->callApi('GET', $endpoint, ['verification_id' => $verification_id]);

        if ($response['error'] || $response['http_code'] === 0) {
            return [
                'success' => false,
                'message' => 'Could not reach the verification service. Please try again.',
                'raw'     => null,
                'data'    => null,
            ];
        }

        if ($response['http_code'] !== 200) {
            $msg = $response['body']['error'] ?? $response['body']['message'] ?? 'Verification lookup failed.';
            return ['success' => false, 'message' => $msg, 'raw' => $response['raw'], 'data' => null];
        }

        $entity = $response['body']['entity'] ?? $response['body']['data'] ?? null;

        if (empty($entity)) {
            return [
                'success' => false,
                'message' => 'No verification record found. Please try again.',
                'raw'     => $response['raw'],
                'data'    => null,
            ];
        }

        if ($type === self::TYPE_VENDOR_BUSINESS) {
            return $this->normaliseBusinessResult($entity, $response['raw']);
        }

        return $this->normalisePersonalResult($entity, $response['raw']);
    }

    // ================================================================
    // PRIVATE: NORMALISE RESULTS
    // ================================================================

    private function normalisePersonalResult(array $entity, ?string $raw): array {
        $first  = ucfirst(strtolower($this->extract($entity, ['first_name','firstname','firstName']) ?? ''));
        $last   = ucfirst(strtolower($this->extract($entity, ['last_name','lastname','surname','lastName']) ?? ''));
        $middle = ucfirst(strtolower($this->extract($entity, ['middle_name','middlename','middleName','other_names']) ?? ''));
        $dob    = $this->extract($entity, ['date_of_birth','birthdate','dob','dateOfBirth']);
        $gender = $this->extract($entity, ['gender','sex']);
        $phone  = $this->extract($entity, ['phone','phone_number','mobile','phoneNumber']);
        $addr   = $this->extract($entity, ['address','residential_address','residentialAddress']);
        $idtype = strtoupper($this->extract($entity, ['id_type','type','verificationType']) ?? '');
        $idnum  = $this->extract($entity, ['nin','bvn','vin','license_number','id_number','number']);

        return [
            'success' => true,
            'message' => 'Verified.',
            'raw'     => $raw,
            'data'    => [
                'first_name'       => $first,
                'last_name'        => $last,
                'middle_name'      => $middle,
                'dob'              => $dob,
                'gender'           => $gender,
                'phone'            => $phone,
                'address'          => $addr,
                'id_type'          => $idtype,
                'id_number'        => $idnum,
                'business_name'    => null,
                'rc_number'        => null,
                'business_type'    => null,
                'business_address' => null,
            ],
        ];
    }

    private function normaliseBusinessResult(array $entity, ?string $raw): array {
        $biz_name = $this->extract($entity, ['company_name','business_name','companyName','businessName','name']) ?? '';
        $rc       = $this->extract($entity, ['rc_number','registration_number','rcNumber','registrationNumber']) ?? '';
        $biz_type = $this->extract($entity, ['company_type','business_type','type']) ?? '';
        $biz_addr = $this->extract($entity, ['address','registered_address','registeredAddress']) ?? '';

        return [
            'success' => true,
            'message' => 'Business verified.',
            'raw'     => $raw,
            'data'    => [
                'first_name'       => null,
                'last_name'        => null,
                'middle_name'      => null,
                'dob'              => null,
                'gender'           => null,
                'phone'            => null,
                'address'          => null,
                'id_type'          => 'CAC',
                'id_number'        => $rc,
                'business_name'    => $biz_name,
                'rc_number'        => $rc,
                'business_type'    => $biz_type,
                'business_address' => $biz_addr,
            ],
        ];
    }

    // ================================================================
    // PRIVATE: HTTP REQUEST
    // ================================================================

    private function callApi(string $method, string $endpoint, array $params = []): array {
        $url = $this->base_url . $endpoint;

        if ($method === 'GET' && !empty($params)) {
            $url .= '?' . http_build_query($params);
        }

        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_HTTPHEADER     => [
                'Authorization: ' . $this->secret_key,
                'Accept: application/json',
                'Content-Type: application/json',
            ],
            CURLOPT_SSL_VERIFYPEER => true,
        ]);

        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
        }

        $raw_body   = curl_exec($ch);
        $http_code  = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curl_error = curl_error($ch);
        curl_close($ch);

        if ($curl_error) {
            return ['http_code' => 0, 'body' => null, 'raw' => null, 'error' => $curl_error];
        }

        return [
            'http_code' => $http_code,
            'body'      => json_decode($raw_body, true),
            'raw'       => $raw_body,
            'error'     => null,
        ];
    }

    // ================================================================
    // PRIVATE: UPDATE USER TABLES
    // ================================================================

    private function updateCustomerAfterVerification(int $user_id, array $data): void {
        $this->db->execute("
            UPDATE customers
            SET first_name      = ?,
                last_name       = ?,
                kyc_status      = 'verified',
                kyc_verified_at = NOW(),
                name_locked     = 1
            WHERE user_id = ?
        ", [$data['first_name'], $data['last_name'], $user_id]);
    }

    private function updateVendorAfterPersonalVerification(int $user_id, array $data): void {
        $this->db->execute("
            UPDATE vendors
            SET personal_kyc_status      = 'verified',
                personal_kyc_verified_at = NOW(),
                rep_name_locked          = 1
            WHERE user_id = ?
        ", [$user_id]);
    }

    private function updateVendorAfterBusinessVerification(int $user_id, array $data): void {
        $this->db->execute("
            UPDATE vendors
            SET business_kyc_status      = 'verified',
                business_kyc_verified_at = NOW(),
                business_name_locked     = 1,
                business_name            = ?
            WHERE user_id = ?
        ", [$data['business_name'], $user_id]);
    }

    // ================================================================
    // PRIVATE: SAVE RECORD TO DB
    // ================================================================

    private function saveRecord(
        int     $user_id,
        string  $user_type,
        string  $verification_type,
        string  $verification_id,
        string  $status,
        array   $data,
        ?string $raw_json,
        string  $failure_reason = ''
    ): void {
        // Remove previous failed attempt of same type
        $this->db->execute(
            "DELETE FROM kyc_verifications
             WHERE user_id = ? AND verification_type = ? AND status != 'verified'",
            [$user_id, $verification_type]
        );

        $this->db->execute("
            INSERT INTO kyc_verifications (
                user_id, user_type, verification_type, verification_id, status,
                verified_first_name, verified_last_name, verified_middle_name,
                verified_dob, verified_gender, verified_phone, verified_address,
                id_type, id_number,
                verified_business_name, verified_rc_number,
                verified_business_type, verified_business_address,
                dojah_response, failure_reason
            ) VALUES (
                ?, ?, ?, ?, ?,
                ?, ?, ?,
                ?, ?, ?, ?,
                ?, ?,
                ?, ?,
                ?, ?,
                ?, ?
            )
        ", [
            $user_id, $user_type, $verification_type, $verification_id, $status,
            $data['first_name']       ?? null,
            $data['last_name']        ?? null,
            $data['middle_name']      ?? null,
            $data['dob']              ?? null,
            $data['gender']           ?? null,
            $data['phone']            ?? null,
            $data['address']          ?? null,
            $data['id_type']          ?? null,
            $data['id_number']        ?? null,
            $data['business_name']    ?? null,
            $data['rc_number']        ?? null,
            $data['business_type']    ?? null,
            $data['business_address'] ?? null,
            $raw_json,
            $failure_reason ?: null,
        ]);
    }

    // ================================================================
    // PUBLIC: QUERY HELPERS
    // ================================================================

    public function isTypeVerified(int $user_id, string $verification_type): bool {
        $row = $this->db->fetch(
            "SELECT id FROM kyc_verifications
             WHERE user_id = ? AND verification_type = ? AND status = 'verified'
             LIMIT 1",
            [$user_id, $verification_type]
        );
        return $row !== null;
    }

    public function isCustomerVerified(int $user_id): bool {
        return $this->isTypeVerified($user_id, self::TYPE_CUSTOMER_IDENTITY);
    }

    public function isVendorPersonalVerified(int $user_id): bool {
        return $this->isTypeVerified($user_id, self::TYPE_VENDOR_PERSONAL);
    }

    public function isVendorBusinessVerified(int $user_id): bool {
        return $this->isTypeVerified($user_id, self::TYPE_VENDOR_BUSINESS);
    }

    public function canVendorListItems(int $user_id): bool {
        return $this->isVendorPersonalVerified($user_id);
    }

    public function canVendorWithdraw(int $user_id, bool $is_registered_business = false): bool {
        if (!$this->isVendorPersonalVerified($user_id)) return false;
        if ($is_registered_business && !$this->isVendorBusinessVerified($user_id)) return false;
        return true;
    }

    public function getVerification(int $user_id, string $verification_type): ?array {
        $row = $this->db->fetch(
            "SELECT * FROM kyc_verifications
             WHERE user_id = ? AND verification_type = ?
             ORDER BY created_at DESC LIMIT 1",
            [$user_id, $verification_type]
        );
        return $row ?: null;
    }

    // ================================================================
    // PRIVATE: FIELD EXTRACTION HELPER
    // ================================================================

    private function extract(array $entity, array $keys): ?string {
        foreach ($keys as $key) {
            if (isset($entity[$key]) && $entity[$key] !== '' && $entity[$key] !== null) {
                return (string)$entity[$key];
            }
        }
        return null;
    }
}