<?php

namespace App\Services;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;

class FinanceApiService
{
    public function settings($schoolId = null)
    {
        $fallbackBaseUrl = (string) config('finance.base_url', '');
        $fallback = [
            'wp_base_url' => $fallbackBaseUrl,
            'base_url' => $fallbackBaseUrl,
            'api_url' => (string) config('finance.api_url', '') ?: $this->defaultApiUrl($fallbackBaseUrl),
            'api_key' => (string) config('finance.api_key', ''),
            'webhook_secret' => (string) config('finance.webhook_secret', ''),
            'sso_secret' => (string) config('finance.sso_secret', ''),
            'payment_url' => (string) config('finance.payment_url', '') ?: $this->defaultPaymentUrl($fallbackBaseUrl),
            'test_admission_number' => (string) config('finance.test_admission_number', ''),
            'auto_detect_test_admission_number' => filter_var(config('finance.auto_detect_test_admission_number', false), FILTER_VALIDATE_BOOLEAN),
            'enabled' => filter_var(config('finance.enabled', false), FILTER_VALIDATE_BOOLEAN),
            'last_sync_at' => null,
            'last_webhook_at' => null,
            'last_connection_status' => null,
            'last_connection_message' => null,
            'last_response_time_ms' => null,
            'last_health_check_at' => null,
            'health_report' => [],
            'local_currency_code' => (string) config('finance.local_currency_code', 'KES'),
            'local_currency_symbol' => (string) config('finance.local_currency_symbol', 'KSh'),
            'international_currency_code' => (string) config('finance.international_currency_code', 'USD'),
            'international_currency_symbol' => (string) config('finance.international_currency_symbol', '$'),
        ];

        $schoolId = $schoolId ?: optional(Auth::user())->school_id;

        if (!Schema::hasTable('finance_settings')) {
            return $this->normalizeSettings($fallback);
        }

        $row = DB::table('finance_settings')
            ->when($schoolId, function ($query) use ($schoolId) {
                $query->where('school_id', $schoolId);
            })
            ->when(!$schoolId, function ($query) {
                $query->whereNull('school_id');
            })
            ->first();

        if (!$row && $schoolId) {
            $row = DB::table('finance_settings')->whereNull('school_id')->first();
        }

        if (!$row) {
            return $this->normalizeSettings($fallback);
        }

        return $this->normalizeSettings([
            'wp_base_url' => $this->firstFilled($this->rowValue($row, 'wp_base_url'), $this->rowValue($row, 'base_url'), $fallback['wp_base_url']),
            'base_url' => $this->firstFilled($this->rowValue($row, 'base_url'), $this->rowValue($row, 'wp_base_url'), $fallback['base_url']),
            'api_url' => $this->rowValue($row, 'api_url'),
            'api_key' => $this->firstFilled($this->rowValue($row, 'api_key'), $fallback['api_key']),
            'webhook_secret' => $this->firstFilled($this->rowValue($row, 'webhook_secret'), $fallback['webhook_secret']),
            'sso_secret' => $this->firstFilled($this->rowValue($row, 'sso_secret'), $fallback['sso_secret']),
            'payment_url' => $this->rowValue($row, 'payment_url'),
            'test_admission_number' => $this->firstFilled($this->rowValue($row, 'test_admission_number'), $fallback['test_admission_number']),
            'auto_detect_test_admission_number' => $fallback['auto_detect_test_admission_number'],
            'enabled' => (bool) $this->rowValue($row, 'enabled', false),
            'last_sync_at' => $this->rowValue($row, 'last_sync_at'),
            'last_webhook_at' => $this->rowValue($row, 'last_webhook_at'),
            'last_connection_status' => $this->rowValue($row, 'last_connection_status'),
            'last_connection_message' => $this->rowValue($row, 'last_connection_message'),
            'last_response_time_ms' => $this->rowValue($row, 'last_response_time_ms'),
            'last_health_check_at' => $this->rowValue($row, 'last_health_check_at'),
            'health_report' => $this->decodeStoredJson($this->rowValue($row, 'health_report')),
            'local_currency_code' => $this->firstFilled($this->rowValue($row, 'local_currency_code'), $fallback['local_currency_code']),
            'local_currency_symbol' => $this->firstFilled($this->rowValue($row, 'local_currency_symbol'), $fallback['local_currency_symbol']),
            'international_currency_code' => $this->firstFilled($this->rowValue($row, 'international_currency_code'), $fallback['international_currency_code']),
            'international_currency_symbol' => $this->firstFilled($this->rowValue($row, 'international_currency_symbol'), $fallback['international_currency_symbol']),
        ]);
    }

    public function isEnabled($schoolId = null)
    {
        return (bool) $this->settings($schoolId)['enabled'];
    }

    public function baseUrl($schoolId = null)
    {
        return (string) $this->settings($schoolId)['wp_base_url'];
    }

    public function apiUrl($schoolId = null)
    {
        return (string) $this->settings($schoolId)['api_url'];
    }

    public function apiKey($schoolId = null)
    {
        return (string) $this->settings($schoolId)['api_key'];
    }

    public function webhookSecret($schoolId = null)
    {
        $settings = $this->settings($schoolId);

        return (string) ($settings['webhook_secret'] ?: $settings['api_key']);
    }

    public function ssoSecret($schoolId = null)
    {
        return (string) ($this->settings($schoolId)['sso_secret'] ?? '');
    }

    public function webhookSecrets($schoolId = null)
    {
        $settings = $this->settings($schoolId);
        $secrets = [
            (string) ($settings['webhook_secret'] ?? ''),
            (string) ($settings['api_key'] ?? ''),
            (string) config('finance.webhook_secret', ''),
            (string) config('finance.api_key', ''),
        ];

        return array_values(array_unique(array_filter($secrets)));
    }

    public function allWebhookSecrets()
    {
        $secrets = $this->webhookSecrets();

        if (Schema::hasTable('finance_settings')) {
            $columns = $this->existingFinanceSettingsColumns(['api_key', 'webhook_secret']);
            if (!empty($columns)) {
                $rows = DB::table('finance_settings')->get($columns);
                foreach ($rows as $row) {
                    $secrets[] = (string) $this->rowValue($row, 'webhook_secret');
                    $secrets[] = (string) $this->rowValue($row, 'api_key');
                }
            }
        }

        return array_values(array_unique(array_filter($secrets)));
    }

    public function knownSourceUrls($schoolId = null)
    {
        $settings = $this->settings($schoolId);
        $urls = [
            $settings['wp_base_url'] ?? '',
            $settings['base_url'] ?? '',
            $settings['payment_url'] ?? '',
            $settings['api_url'] ?? '',
            (string) config('finance.base_url', ''),
        ];

        if (!$schoolId && Schema::hasTable('finance_settings')) {
            $columns = $this->existingFinanceSettingsColumns(['wp_base_url', 'base_url', 'payment_url', 'api_url']);
            if (!empty($columns)) {
                $rows = DB::table('finance_settings')->get($columns);
                foreach ($rows as $row) {
                    foreach ($columns as $column) {
                        $urls[] = (string) $this->rowValue($row, $column);
                    }
                }
            }
        }

        return array_values(array_unique(array_filter(array_map(function ($url) {
            return rtrim(trim((string) $url), '/');
        }, $urls))));
    }

    public function getFinanceSummary($admissionNumber, $schoolId = null)
    {
        $settings = $this->settings($schoolId);
        $admissionNumber = trim((string) $admissionNumber);
        $endpoint = $this->apiEndpoint($settings, 'student/' . rawurlencode($admissionNumber) . '/finance');

        if (!$settings['enabled'] || $endpoint === '' || $settings['api_key'] === '' || $admissionNumber === '') {
            return null;
        }

        try {
            $apiKey = trim((string) $settings['api_key']);
            $response = Http::acceptJson()
                ->withHeaders($this->apiHeaders($apiKey))
                ->timeout(10)
                ->get($endpoint);

            if (!$response->successful()) {
                Log::warning('Finance summary request failed.', [
                    'status' => $response->status(),
                    'admission_number' => $admissionNumber,
                ]);

                return null;
            }

            return $this->decodeJsonResponse($response);
        } catch (\Throwable $e) {
            Log::warning('Finance summary request failed.', [
                'admission_number' => $admissionNumber,
                'error' => $e->getMessage(),
            ]);

            return null;
        }
    }

    public function getFinanceInvoices($admissionNumber, $schoolId = null)
    {
        $settings = $this->settings($schoolId);
        $admissionNumber = trim((string) $admissionNumber);
        $endpoint = $this->apiEndpoint($settings, 'student/' . rawurlencode($admissionNumber) . '/invoices');

        if (!$settings['enabled'] || $endpoint === '' || $settings['api_key'] === '' || $admissionNumber === '') {
            return null;
        }

        try {
            $apiKey = trim((string) $settings['api_key']);
            $response = Http::acceptJson()
                ->withHeaders($this->apiHeaders($apiKey))
                ->timeout(10)
                ->get($endpoint);

            if (!$response->successful()) {
                Log::warning('Finance invoices request failed.', [
                    'status' => $response->status(),
                    'admission_number' => $admissionNumber,
                ]);

                return null;
            }

            return $this->decodeJsonResponse($response);
        } catch (\Throwable $e) {
            Log::warning('Finance invoices request failed.', [
                'admission_number' => $admissionNumber,
                'error' => $e->getMessage(),
            ]);

            return null;
        }
    }

    public function ping($schoolId = null)
    {
        return (bool) ($this->pingDetails($schoolId)['status'] ?? false);
    }

    public function pingDetails($schoolId = null)
    {
        $settings = $this->settings($schoolId);
        $endpoint = $this->apiEndpoint($settings, 'ping');

        if ($endpoint === '') {
            return [
                'status' => false,
                'message' => 'WordPress finance API URL is not configured.',
                'code' => null,
                'response' => null,
                'response_time' => null,
                'url' => $endpoint,
            ];
        }

        try {
            $response = Http::acceptJson()
                ->timeout(10)
                ->get($endpoint);

            $data = $this->decodeJsonResponse($response);
            $responseTime = $response->transferStats ? $response->transferStats->getTransferTime() : null;

            Log::info('WP Ping Response', [
                'url' => $endpoint,
                'response' => $data,
                'status_code' => $response->status(),
            ]);

            if (!$response->ok()) {
                return [
                    'status' => false,
                    'message' => 'HTTP request failed',
                    'code' => $response->status(),
                    'response' => is_array($data) ? $data : $response->body(),
                    'response_time' => $responseTime,
                    'url' => $endpoint,
                ];
            }

            if (!is_array($data)) {
                return [
                    'status' => false,
                    'message' => 'Invalid JSON ping response from WordPress',
                    'code' => $response->status(),
                    'response' => $response->body(),
                    'response_time' => $responseTime,
                    'url' => $endpoint,
                ];
            }

            $statusOk = strtolower((string) ($data['status'] ?? '')) === 'ok';
            $successOk = filter_var($data['success'] ?? false, FILTER_VALIDATE_BOOLEAN);

            if (!$statusOk && !$successOk) {
                return [
                    'status' => false,
                    'message' => 'Invalid ping response from WordPress',
                    'code' => $response->status(),
                    'response' => $data,
                    'response_time' => $responseTime,
                    'url' => $endpoint,
                ];
            }

            return [
                'status' => true,
                'message' => 'Connected successfully',
                'code' => $response->status(),
                'response' => $data,
                'response_time' => $responseTime,
                'url' => $endpoint,
            ];
        } catch (\Throwable $e) {
            Log::warning('Finance ping failed.', [
                'url' => $endpoint,
                'error' => $e->getMessage(),
            ]);

            return [
                'status' => false,
                'message' => 'HTTP request failed: ' . $e->getMessage(),
                'code' => null,
                'response' => null,
                'response_time' => null,
                'url' => $endpoint,
            ];
        }
    }

    public function payUrl($admissionNumber, $schoolId = null)
    {
        $settings = $this->settings($schoolId);
        $paymentUrl = (string) ($settings['payment_url'] ?? '');
        $admissionNumber = trim((string) $admissionNumber);

        if ($paymentUrl === '' || $admissionNumber === '') {
            return '';
        }

        return $paymentUrl . '?adm=' . rawurlencode($admissionNumber);
    }

    public function ssoPayUrl($token, $schoolId = null)
    {
        $settings = $this->settings($schoolId);
        $paymentUrl = (string) ($settings['payment_url'] ?? '');
        $token = trim((string) $token);

        if ($paymentUrl === '' || $token === '') {
            return '';
        }

        return $this->urlWithQuery($paymentUrl, ['sso_token' => $token]);
    }

    public function fullHealthCheck($schoolId = null)
    {
        $settings = $this->settings($schoolId);
        $started = microtime(true);
        $checks = [];

        $publicPing = $this->pingDetails($schoolId);
        $checks[] = $this->healthRow('Public WordPress ping', (bool) ($publicPing['status'] ?? false), $publicPing['message'] ?? 'Not checked', $publicPing);

        $protectedStatus = false;
        $protectedMessage = '';
        $protectedSuggestedFix = null;
        $protectedRowStatus = null;
        $testAdmission = $this->normalizeAdmissionNumberSetting($settings['test_admission_number'] ?? '');
        $testAdmissionSource = $testAdmission !== '' ? 'configured' : 'missing';

        if ($testAdmission === '' && !empty($settings['auto_detect_test_admission_number'])) {
            $testAdmission = $this->findFirstActiveStudentAdmissionNumber($schoolId);
            $testAdmissionSource = $testAdmission !== '' ? 'auto_detected' : 'missing';
        }

        if (empty($settings['api_url'])) {
            $protectedMessage = 'Finance API URL is not configured.';
            $protectedSuggestedFix = 'Add the WordPress Finance API URL in Finance Settings.';
        } elseif (empty($settings['api_key'])) {
            $protectedMessage = 'Finance API key is not configured.';
            $protectedSuggestedFix = 'Add the Finance API key in Finance Settings and WordPress wallet settings.';
        } elseif ($testAdmission === '') {
            $protectedMessage = 'Protected API test skipped because no test admission number is configured.';
            $protectedRowStatus = 'warning';
            $protectedSuggestedFix = 'Add a Protected API Test Admission Number in Finance Settings. The same admission number must exist in WordPress as user_login or admission_number user meta.';
        } else {
            $endpoint = $this->apiEndpoint($settings, 'student/' . rawurlencode($testAdmission) . '/finance');
            try {
                $response = Http::acceptJson()
                    ->withHeaders($this->apiHeaders((string) $settings['api_key']))
                    ->timeout(10)
                    ->get($endpoint);
                $protectedStatus = $response->successful();
                $errorCode = $this->financeResponseErrorCode($response);
                $protectedMessage = $this->protectedFinanceMessage($response->status(), $protectedStatus, $errorCode);
                $protectedSuggestedFix = $this->protectedFinanceSuggestedFix($response->status(), $errorCode, $protectedStatus);
            } catch (\Throwable $e) {
                $protectedMessage = 'Protected finance API request failed: ' . $e->getMessage();
            }
        }
        $checks[] = $this->healthRow('Protected finance API request', $protectedStatus, $protectedMessage, [
            'test_admission_source' => $testAdmissionSource,
        ], $protectedRowStatus, $protectedSuggestedFix);

        $checks[] = $this->healthRow('Laravel ping endpoint', url('/api/finance/ping') !== '', 'Laravel finance ping route should be reachable at ' . url('/api/finance/ping') . '.');
        $checks[] = $this->healthRow('Webhook dry-run readiness', !empty($settings['webhook_secret']) || !empty($settings['api_key']), 'Webhook dry-run uses the configured webhook/API secret without sending a real payment.');
        $checks[] = $this->healthRow('SSO dry-run readiness', !empty($settings['sso_secret']) && !empty($settings['payment_url']), 'SSO token generation can run when SSO secret and payment URL are configured.');
        $checks[] = $this->healthRow('Email configuration', config('mail.default') !== '', 'Mail driver: ' . (string) config('mail.default'));
        $checks[] = $this->healthRow('PDF generation readiness', class_exists(\Barryvdh\DomPDF\Facade\Pdf::class) || class_exists(\Barryvdh\DomPDF\PDF::class), 'Dompdf package is available for Laravel-side PDFs.');
        $checks[] = $this->healthRow('Queue/background worker', config('queue.default') !== '', 'Queue driver: ' . (string) config('queue.default'));
        $checks[] = $this->healthRow('C2B endpoint availability', !empty($settings['wp_base_url']), 'Expected WordPress C2B endpoints under /wp-json/rbytes/v1/mpesa/c2b/*.');
        $checks[] = $this->healthRow('Checkout preflight', !empty($settings['payment_url']), 'Payment URL configured: ' . (string) ($settings['payment_url'] ?? ''));

        $summary = ['passed' => 0, 'warning' => 0, 'failed' => 0];
        foreach ($checks as $row) {
            $status = (string) ($row['status'] ?? 'failed');
            if (!array_key_exists($status, $summary)) {
                $status = 'failed';
            }
            $summary[$status]++;
        }

        return [
            'checked_at' => now()->toDateTimeString(),
            'duration_ms' => (int) round((microtime(true) - $started) * 1000),
            'checks' => $checks,
            'summary' => $summary,
        ];
    }

    private function normalizeSettings(array $settings)
    {
        $wpBaseUrl = $this->cleanUrl($this->firstFilled($settings['wp_base_url'] ?? '', $settings['base_url'] ?? ''));
        $apiUrl = $this->normalizeApiUrl($settings['api_url'] ?? '');
        $paymentUrl = $this->cleanUrl($settings['payment_url'] ?? '');

        if ($apiUrl === '' && $wpBaseUrl !== '') {
            $apiUrl = $this->defaultApiUrl($wpBaseUrl);
        }

        if ($paymentUrl === '' && $wpBaseUrl !== '') {
            $paymentUrl = $this->defaultPaymentUrl($wpBaseUrl);
        }

        return [
            'wp_base_url' => $wpBaseUrl,
            'base_url' => $wpBaseUrl,
            'api_url' => $apiUrl,
            'api_key' => trim((string) ($settings['api_key'] ?? '')),
            'webhook_secret' => trim((string) ($settings['webhook_secret'] ?? '')),
            'sso_secret' => trim((string) ($settings['sso_secret'] ?? config('finance.sso_secret', ''))),
            'payment_url' => $paymentUrl,
            'test_admission_number' => $this->normalizeAdmissionNumberSetting($settings['test_admission_number'] ?? config('finance.test_admission_number', '')),
            'auto_detect_test_admission_number' => filter_var($settings['auto_detect_test_admission_number'] ?? config('finance.auto_detect_test_admission_number', false), FILTER_VALIDATE_BOOLEAN),
            'enabled' => filter_var($settings['enabled'] ?? false, FILTER_VALIDATE_BOOLEAN),
            'last_sync_at' => $settings['last_sync_at'] ?? null,
            'last_webhook_at' => $settings['last_webhook_at'] ?? null,
            'last_connection_status' => $settings['last_connection_status'] ?? null,
            'last_connection_message' => $settings['last_connection_message'] ?? null,
            'last_response_time_ms' => $settings['last_response_time_ms'] ?? null,
            'last_health_check_at' => $settings['last_health_check_at'] ?? null,
            'health_report' => is_array($settings['health_report'] ?? null) ? $settings['health_report'] : [],
            'local_currency_code' => trim((string) ($settings['local_currency_code'] ?? config('finance.local_currency_code', 'KES'))),
            'local_currency_symbol' => trim((string) ($settings['local_currency_symbol'] ?? config('finance.local_currency_symbol', 'KSh'))),
            'international_currency_code' => trim((string) ($settings['international_currency_code'] ?? config('finance.international_currency_code', 'USD'))),
            'international_currency_symbol' => trim((string) ($settings['international_currency_symbol'] ?? config('finance.international_currency_symbol', '$'))),
        ];
    }

    private function apiEndpoint(array $settings, $path)
    {
        $apiUrl = $this->normalizeApiUrl($settings['api_url'] ?? '');

        return $apiUrl !== '' ? $apiUrl . '/' . ltrim((string) $path, '/') : '';
    }

    private function normalizeApiUrl($apiUrl)
    {
        $apiUrl = $this->cleanUrl($apiUrl);
        if ($apiUrl === '') {
            return '';
        }

        if (preg_match('#/wp-json/?$#', $apiUrl)) {
            return $apiUrl . '/rbytes/v1';
        }

        return $apiUrl;
    }

    private function defaultApiUrl($wpBaseUrl)
    {
        $wpBaseUrl = $this->cleanUrl($wpBaseUrl);
        if ($wpBaseUrl === '') {
            return '';
        }

        if (preg_match('#/wp-json/rbytes/v1/?$#', $wpBaseUrl)) {
            return $wpBaseUrl;
        }

        if (preg_match('#/wp-json/?$#', $wpBaseUrl)) {
            return $wpBaseUrl . '/rbytes/v1';
        }

        return $wpBaseUrl . '/wp-json/rbytes/v1';
    }

    private function defaultPaymentUrl($wpBaseUrl)
    {
        $wpBaseUrl = $this->cleanUrl($wpBaseUrl);
        if ($wpBaseUrl === '') {
            return '';
        }

        if (preg_match('#/pay/?$#', $wpBaseUrl)) {
            return $wpBaseUrl;
        }

        return $wpBaseUrl . '/pay';
    }

    private function cleanUrl($url)
    {
        return rtrim(trim((string) $url), '/');
    }

    private function urlWithQuery($url, array $params)
    {
        $separator = strpos((string) $url, '?') === false ? '?' : '&';

        return (string) $url . $separator . http_build_query($params, '', '&', PHP_QUERY_RFC3986);
    }

    private function firstFilled()
    {
        foreach (func_get_args() as $value) {
            $value = trim((string) $value);
            if ($value !== '') {
                return $value;
            }
        }

        return '';
    }

    private function rowValue($row, $column, $default = '')
    {
        return is_object($row) && property_exists($row, $column) ? $row->{$column} : $default;
    }

    private function decodeStoredJson($value)
    {
        if (is_array($value)) {
            return $value;
        }

        $decoded = json_decode((string) $value, true);

        return is_array($decoded) ? $decoded : [];
    }

    private function findFirstActiveStudentAdmissionNumber($schoolId = null)
    {
        $admissionNumber = $this->firstStudentAdmissionFromTable('sm_students', 'admission_no', $schoolId);
        if ($admissionNumber !== '') {
            return $admissionNumber;
        }

        return $this->firstStudentAdmissionFromTable('users', 'admission_number', $schoolId);
    }

    private function firstStudentAdmissionFromTable($table, $column, $schoolId = null)
    {
        if (!Schema::hasTable($table) || !Schema::hasColumn($table, $column)) {
            return '';
        }

        $query = DB::table($table)
            ->select($column)
            ->whereNotNull($column)
            ->where($column, '<>', '');

        if ($schoolId && Schema::hasColumn($table, 'school_id')) {
            $query->where('school_id', $schoolId);
        }

        if (Schema::hasColumn($table, 'active_status')) {
            $query->where('active_status', 1);
        }

        if ($table === 'users' && Schema::hasColumn($table, 'role_id')) {
            $query->where('role_id', 2);
        }

        $row = $query->orderBy('id')->first();

        return $this->normalizeAdmissionNumberSetting($row ? $row->{$column} : '');
    }

    private function normalizeAdmissionNumberSetting($value)
    {
        return strtoupper(trim((string) $value));
    }

    private function financeResponseErrorCode($response)
    {
        $data = $this->decodeJsonResponse($response);

        return is_array($data) ? (string) ($data['code'] ?? '') : '';
    }

    private function protectedFinanceMessage($status, $successful, $errorCode = '')
    {
        if ($successful) {
            return 'Protected finance API request succeeded.';
        }

        if ((int) $status === 404 || $errorCode === 'rbytes_student_not_found') {
            return 'WordPress did not find a wallet student with this admission number. Ensure the Laravel admission number exists in WordPress as user_login or admission_number user meta.';
        }

        if ((int) $status === 401 && in_array($errorCode, ['rbytes_missing_signature', 'rbytes_stale_signature', 'rbytes_invalid_signature'], true)) {
            return 'Signed request rejected. Confirm signed reads setting, SSO/API secret, timestamps, and source headers.';
        }

        if ((int) $status === 401) {
            return 'WordPress rejected the API key. Confirm the same API key is saved on both Laravel and WordPress.';
        }

        if ((int) $status === 403) {
            return 'WordPress rejected the protected finance API request. Confirm source whitelist and signed protected read settings.';
        }

        return 'Protected finance API returned HTTP ' . (int) $status . '.';
    }

    private function protectedFinanceSuggestedFix($status, $errorCode, $successful)
    {
        if ($successful) {
            return '';
        }

        if ((int) $status === 404 || $errorCode === 'rbytes_student_not_found') {
            return 'Use an admission number that exists in WordPress as user_login or admission_number user meta.';
        }

        if ((int) $status === 401 && in_array($errorCode, ['rbytes_missing_signature', 'rbytes_stale_signature', 'rbytes_invalid_signature'], true)) {
            return 'Confirm signed reads, shared secret, timestamp tolerance, and X-RBYTES-SOURCE configuration.';
        }

        if ((int) $status === 401) {
            return 'Confirm Laravel Finance API key matches WordPress API Secret Key.';
        }

        if ((int) $status === 403) {
            return 'Confirm portal source whitelist and signed protected read settings in WordPress.';
        }

        return 'Review the finance settings on both Laravel and WordPress, then rerun the health check.';
    }

    private function healthRow($name, $passed, $message, array $meta = [], $status = null, $suggestedFix = null)
    {
        $status = $status ?: ($passed ? 'passed' : 'failed');

        return [
            'name' => (string) $name,
            'status' => $status,
            'message' => (string) $message,
            'meta' => $meta,
            'suggested_fix' => $suggestedFix !== null ? (string) $suggestedFix : ($passed ? '' : 'Review the finance settings on both Laravel and WordPress, then rerun the health check.'),
        ];
    }

    private function existingFinanceSettingsColumns(array $columns)
    {
        return array_values(array_filter($columns, function ($column) {
            return Schema::hasColumn('finance_settings', $column);
        }));
    }

    private function apiHeaders($apiKey, $body = '', $method = 'GET')
    {
        $timestamp = (string) time();
        $signature = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . (string) $body, trim((string) $apiKey));

        return [
            'Authorization' => 'Bearer ' . trim((string) $apiKey),
            'X-RBYTES-SIGNATURE' => $signature,
            'X-RBYTES-TIMESTAMP' => $timestamp,
            'X-RBYTES-SOURCE' => rtrim((string) config('app.url', ''), '/'),
            'X-RBYTES-METHOD' => strtoupper((string) $method),
        ];
    }

    private function decodeJsonResponse($response)
    {
        $body = (string) $response->body();
        $body = $this->stripJsonPrefix($body);

        return $this->normalizeFinancePayload(json_decode($body, true));
    }

    private function normalizeFinancePayload($value)
    {
        if (is_array($value)) {
            $normalized = [];
            foreach ($value as $key => $item) {
                $normalized[$key] = $this->normalizeFinancePayload($item);
            }

            return $normalized;
        }

        if (is_string($value)) {
            $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
            $value = str_replace(["\xc2\xa0", '&nbsp;'], ' ', $value);
            $normalized = preg_replace('/\s+/u', ' ', $value);

            return trim(is_string($normalized) ? $normalized : $value);
        }

        return $value;
    }

    private function stripJsonPrefix($body)
    {
        $body = (string) $body;

        if (substr($body, 0, 3) === "\xEF\xBB\xBF") {
            $body = substr($body, 3);
        }

        $trimmed = ltrim($body);
        if (substr($trimmed, 0, 3) === "\xEF\xBB\xBF") {
            $trimmed = substr($trimmed, 3);
        }

        return ltrim($trimmed);
    }
}
