<?php

namespace App\Services;

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

class NinVerificationApiService
{
    private string $baseUrl;
    private ?string $appId;
    private ?string $secret;
    private int $timeout;

    public function __construct()
    {
        $env = config('nin.dojah_env', 'sandbox');

        $this->baseUrl = $env === 'live'
            ? 'https://api.dojah.io'
            : 'https://sandbox.dojah.io';

        $this->appId   = config('nin.dojah_app_id');
        $this->secret  = config('nin.dojah_secret');
        $this->timeout = config('nin.timeout', 30);
    }

    /**
     * Verify a NIN against the Dojah API.
     *
     * Dojah docs: https://docs.dojah.io/kyc/nin-lookup
     * Sandbox base URL : https://sandbox.dojah.io
     * Live base URL    : https://api.dojah.io
     * Endpoint         : GET /api/v1/kyc/nin?nin={nin}
     * Headers          : AppId, Authorization (raw secret — not Bearer)
     * Test NIN (sandbox): 70123456789
     *
     * @param string $nin Decrypted 11-digit NIN
     * @return array ['success', 'verified', 'message', 'service_unavailable'?, 'data'?, 'report_id'?]
     */
    public function verifyNin(string $nin): array
    {
        $reference    = 'NIN_' . now()->format('ymdHis') . '_' . strtoupper(Str::random(6));
        $requestStart = microtime(true);

        try {
            Log::channel('nin_verification')->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
            Log::channel('nin_verification')->info('NIN VERIFICATION REQUEST INITIATED', [
                'reference'       => $reference,
                'timestamp'       => now()->toIso8601String(),
                'nin_masked'      => substr($nin, 0, 3) . '****' . substr($nin, -2),
                'environment'     => config('nin.dojah_env'),
                'endpoint'        => $this->baseUrl . '/api/v1/kyc/nin',
                'timeout_seconds' => $this->timeout,
            ]);

            $response = Http::withHeaders([
                'AppId'         => $this->appId,
                'Authorization' => $this->secret,
                'Accept'        => 'application/json',
            ])
            ->timeout($this->timeout)
            ->get($this->baseUrl . '/api/v1/kyc/nin', [
                'nin'                => $nin,
                'customer_reference' => $reference,
            ]);

            $duration = round((microtime(true) - $requestStart) * 1000, 2);

            Log::channel('nin_verification')->info('NIN VERIFICATION RESPONSE RECEIVED', [
                'reference'   => $reference,
                'duration_ms' => $duration,
                'status_code' => $response->status(),
                'entity_keys' => $response->successful() ? array_keys((array) $response->json('entity')) : [],
            ]);
            Log::channel('nin_verification')->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');

            if ($response->successful()) {
                $entity = $response->json('entity');

                if (empty($entity)) {
                    return [
                        'success'   => false,
                        'verified'  => false,
                        'message'   => 'NIN not found.',
                        'report_id' => $reference,
                    ];
                }

                return [
                    'success'   => true,
                    'verified'  => true,
                    'message'   => 'NIN verified successfully.',
                    'data'      => $entity,
                    'report_id' => $reference,
                ];
            }

            $errorMessage = $this->resolveErrorMessage($response->status(), $response->json());

            Log::channel('nin_verification')->error('NIN VERIFICATION API ERROR', [
                'reference'   => $reference,
                'duration_ms' => $duration,
                'status_code' => $response->status(),
                'error'       => $errorMessage,
            ]);

            $serviceUnavailable = in_array($response->status(), [401, 402, 403, 424, 429, 503]);

            return [
                'success'             => false,
                'verified'            => false,
                'service_unavailable' => $serviceUnavailable,
                'message'             => $errorMessage,
                'error_code'          => $response->status(),
                'report_id'           => $reference,
            ];

        } catch (\Illuminate\Http\Client\ConnectionException $e) {
            $duration = round((microtime(true) - $requestStart) * 1000, 2);

            Log::channel('nin_verification')->error('NIN VERIFICATION CONNECTION ERROR', [
                'reference'   => $reference,
                'duration_ms' => $duration,
                'error'       => $e->getMessage(),
            ]);
            Log::channel('nin_verification')->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');

            return [
                'success'             => false,
                'verified'            => false,
                'service_unavailable' => true,
                'message'             => 'NIN verification service is currently unavailable. Please try again later.',
            ];

        } catch (\Exception $e) {
            $duration = round((microtime(true) - $requestStart) * 1000, 2);

            Log::channel('nin_verification')->error('NIN VERIFICATION UNEXPECTED ERROR', [
                'reference'   => $reference,
                'duration_ms' => $duration,
                'error'       => $e->getMessage(),
            ]);
            Log::channel('nin_verification')->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');

            return [
                'success'             => false,
                'verified'            => false,
                'service_unavailable' => true,
                'message'             => 'NIN verification service is currently unavailable. Please try again later.',
            ];
        }
    }

    /**
     * Look up NIN data via a phone number against the Dojah API.
     *
     * Endpoint: GET /api/v1/kyc/phone_number?phone_number={phone}&nin=true
     * Returns:  nin, photo, first_name, last_name, middle_name, phone_number,
     *           date_of_birth, gender
     *
     * @param string $phoneNumber Phone number to look up
     * @return array ['success', 'verified', 'message', 'service_unavailable'?, 'data'?, 'report_id'?]
     */
    public function verifyNinByPhone(string $phoneNumber): array
    {
        $reference    = 'NIN_PHONE_' . now()->format('ymdHis') . '_' . strtoupper(Str::random(6));
        $requestStart = microtime(true);

        try {
            Log::channel('nin_verification')->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
            Log::channel('nin_verification')->info('NIN BY PHONE VERIFICATION REQUEST INITIATED', [
                'reference'       => $reference,
                'timestamp'       => now()->toIso8601String(),
                'phone_masked'    => substr($phoneNumber, 0, 4) . '****' . substr($phoneNumber, -2),
                'environment'     => config('nin.dojah_env'),
                'endpoint'        => $this->baseUrl . '/api/v1/kyc/phone_number',
                'timeout_seconds' => $this->timeout,
            ]);

            $response = Http::withHeaders([
                'AppId'         => $this->appId,
                'Authorization' => $this->secret,
                'Accept'        => 'application/json',
            ])
            ->timeout($this->timeout)
            ->get($this->baseUrl . '/api/v1/kyc/phone_number', [
                'phone_number' => $phoneNumber,
                'nin'          => 'true',
            ]);

            $duration = round((microtime(true) - $requestStart) * 1000, 2);

            Log::channel('nin_verification')->info('NIN BY PHONE VERIFICATION RESPONSE RECEIVED', [
                'reference'   => $reference,
                'duration_ms' => $duration,
                'status_code' => $response->status(),
                'entity_keys' => $response->successful() ? array_keys((array) $response->json('entity')) : [],
            ]);
            Log::channel('nin_verification')->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');

            if ($response->successful()) {
                $entity = $response->json('entity');

                if (empty($entity)) {
                    return [
                        'success'   => false,
                        'verified'  => false,
                        'message'   => 'No NIN record found for this phone number.',
                        'report_id' => $reference,
                    ];
                }

                return [
                    'success'   => true,
                    'verified'  => true,
                    'message'   => 'NIN record retrieved successfully.',
                    'data'      => $entity,
                    'report_id' => $reference,
                ];
            }

            $errorMessage = $this->resolvePhoneErrorMessage($response->status(), $response->json());

            Log::channel('nin_verification')->error('NIN BY PHONE VERIFICATION API ERROR', [
                'reference'   => $reference,
                'duration_ms' => $duration,
                'status_code' => $response->status(),
                'error'       => $errorMessage,
            ]);

            $serviceUnavailable = in_array($response->status(), [401, 402, 403, 424, 429, 503]);

            return [
                'success'             => false,
                'verified'            => false,
                'service_unavailable' => $serviceUnavailable,
                'message'             => $errorMessage,
                'error_code'          => $response->status(),
                'report_id'           => $reference,
            ];

        } catch (\Illuminate\Http\Client\ConnectionException $e) {
            $duration = round((microtime(true) - $requestStart) * 1000, 2);

            Log::channel('nin_verification')->error('NIN BY PHONE VERIFICATION CONNECTION ERROR', [
                'reference'   => $reference,
                'duration_ms' => $duration,
                'error'       => $e->getMessage(),
            ]);
            Log::channel('nin_verification')->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');

            return [
                'success'             => false,
                'verified'            => false,
                'service_unavailable' => true,
                'message'             => 'NIN verification service is currently unavailable. Please try again later.',
            ];

        } catch (\Exception $e) {
            $duration = round((microtime(true) - $requestStart) * 1000, 2);

            Log::channel('nin_verification')->error('NIN BY PHONE VERIFICATION UNEXPECTED ERROR', [
                'reference'   => $reference,
                'duration_ms' => $duration,
                'error'       => $e->getMessage(),
            ]);
            Log::channel('nin_verification')->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');

            return [
                'success'             => false,
                'verified'            => false,
                'service_unavailable' => true,
                'message'             => 'NIN verification service is currently unavailable. Please try again later.',
            ];
        }
    }

    private function resolveErrorMessage(int $status, ?array $body): string
    {
        return match ($status) {
            400 => 'Invalid NIN or request parameters.',
            401 => 'NIN verification service authentication failed. Check your API credentials.',
            402 => 'NIN verification service wallet balance is insufficient.',
            403 => 'Access denied. Your plan does not include NIN verification.',
            424 => 'NIN verification upstream service is unavailable. Please try again later.',
            429 => 'NIN verification rate limit exceeded. Please try again shortly.',
            default => $body['error'] ?? $body['message'] ?? 'NIN verification failed.',
        };
    }

    private function resolvePhoneErrorMessage(int $status, ?array $body): string
    {
        return match ($status) {
            400 => 'Invalid phone number or request parameters.',
            401 => 'NIN verification service authentication failed. Check your API credentials.',
            402 => 'NIN verification service wallet balance is insufficient.',
            403 => 'Access denied. Your plan does not include this verification.',
            404 => 'No NIN record found for this phone number.',
            424 => 'NIN verification upstream service is unavailable. Please try again later.',
            429 => 'NIN verification rate limit exceeded. Please try again shortly.',
            default => $body['error'] ?? $body['message'] ?? 'NIN lookup by phone number failed.',
        };
    }
}
