<?php
/**
 * nightsbridge_connector.php
 * Place: /rooms/modules/channel_manager/providers/nightsbridge_connector.php
 *
 * NightsBridge PMS connector wrapper.
 *
 * IMPORTANT:
 * - NightsBridge API credentials/endpoints must be supplied by NightsBridge.
 * - Keep live mode disabled until NightsBridge confirms your PMS connector credentials.
 *
 * Live mode:
 * Add this to channel connection notes only after approval/testing:
 * NIGHTSBRIDGE_LIVE_ENABLED=1
 *
 * Recommended channel connection:
 * provider: nightsbridge
 * api_base_url: supplied by NightsBridge
 * api_username: supplied by NightsBridge, if used
 * api_password: supplied by NightsBridge, if used
 * api_token: supplied by NightsBridge, if used
 * external_property_id: NightsBridge property/establishment ID
 */

if (!function_exists('nb_decrypt_secret')) {
    function nb_decrypt_secret(?string $value): string
    {
        $value = (string)$value;
        if ($value === '') return '';

        $decoded = base64_decode($value, true);
        return $decoded === false ? $value : $decoded;
    }
}

if (!function_exists('nb_live_enabled')) {
    function nb_live_enabled(array $connection): bool
    {
        return strpos((string)($connection['notes'] ?? ''), 'NIGHTSBRIDGE_LIVE_ENABLED=1') !== false;
    }
}

if (!function_exists('nb_base_url')) {
    function nb_base_url(array $connection): string
    {
        $url = trim((string)($connection['api_base_url'] ?? ''));

        /*
         * NightsBridge must provide the real PMS connector base URL.
         * This placeholder keeps the connector safe until credentials are supplied.
         */
        if ($url === '') {
            $url = 'https://api.nightsbridge.com';
        }

        return rtrim($url, '/');
    }
}

if (!function_exists('nb_auth_headers')) {
    function nb_auth_headers(array $connection, string $contentType = 'application/json'): array
    {
        $headers = [
            'Content-Type: ' . $contentType,
            'Accept: application/json',
        ];

        $token = nb_decrypt_secret($connection['api_token_enc'] ?? '');
        if ($token !== '') {
            $headers[] = 'Authorization: Bearer ' . $token;
            return $headers;
        }

        $username = trim((string)($connection['api_username'] ?? ''));
        $password = nb_decrypt_secret($connection['api_password_enc'] ?? '');

        if ($username !== '' && $password !== '') {
            $headers[] = 'Authorization: Basic ' . base64_encode($username . ':' . $password);
        }

        return $headers;
    }
}

if (!function_exists('nb_http_request')) {
    function nb_http_request(array $connection, string $method, string $endpoint, array $payload = []): array
    {
        if (!nb_live_enabled($connection)) {
            return [
                'ok' => false,
                'blocked' => true,
                'status' => 0,
                'message' => 'NightsBridge live mode is disabled. Add NIGHTSBRIDGE_LIVE_ENABLED=1 to connection notes after NightsBridge approves connector credentials.',
                'endpoint' => $endpoint,
                'request_payload' => $payload,
                'response_body' => '',
            ];
        }

        $url = nb_base_url($connection) . '/' . ltrim($endpoint, '/');

        $ch = curl_init($url);
        $headers = nb_auth_headers($connection);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 45,
            CURLOPT_CUSTOMREQUEST => strtoupper($method),
            CURLOPT_HTTPHEADER => $headers,
        ]);

        if (strtoupper($method) !== 'GET') {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
        }

        $responseBody = curl_exec($ch);
        $error = curl_error($ch);
        $status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

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

        return [
            'ok' => $error === '' && $status >= 200 && $status < 300,
            'blocked' => false,
            'status' => $status,
            'message' => $error !== '' ? $error : ('HTTP ' . $status),
            'endpoint' => $endpoint,
            'request_payload' => $payload,
            'response_body' => (string)$responseBody,
            'response_json' => is_array($decoded) ? $decoded : null,
        ];
    }
}

if (!function_exists('nb_build_availability_payload')) {
    function nb_build_availability_payload(array $connection, array $availabilityRows): array
    {
        return [
            'property_id' => (string)($connection['external_property_id'] ?? ''),
            'source' => 'pms',
            'generated_at' => date('c'),
            'availability' => array_map(function ($row) {
                return [
                    'date' => (string)($row['date'] ?? ''),
                    'room_id' => (string)($row['external_room_id'] ?? ''),
                    'available' => max(0, (int)($row['available'] ?? 0)),
                    'closed' => !empty($row['closed']) || (int)($row['available'] ?? 0) <= 0,
                ];
            }, $availabilityRows),
        ];
    }
}

if (!function_exists('nb_build_rates_payload')) {
    function nb_build_rates_payload(array $connection, array $rateRows): array
    {
        return [
            'property_id' => (string)($connection['external_property_id'] ?? ''),
            'source' => 'pms',
            'generated_at' => date('c'),
            'rates' => array_map(function ($row) {
                return [
                    'date' => (string)($row['date'] ?? ''),
                    'rate_id' => (string)($row['external_rate_id'] ?? ''),
                    'amount' => round((float)($row['amount'] ?? 0), 2),
                    'currency' => (string)($row['currency'] ?? 'USD'),
                    'closed' => !empty($row['closed']),
                ];
            }, $rateRows),
        ];
    }
}

if (!function_exists('nb_normalize_booking')) {
    function nb_normalize_booking(array $booking): array
    {
        $guest = $booking['guest'] ?? [];
        if (!is_array($guest)) $guest = [];

        return [
            'external_booking_id' => (string)($booking['booking_id'] ?? $booking['reservation_id'] ?? $booking['id'] ?? ''),
            'external_property_id' => (string)($booking['property_id'] ?? $booking['establishment_id'] ?? ''),
            'guest_name' => (string)($booking['guest_name'] ?? trim((string)($guest['first_name'] ?? '') . ' ' . (string)($guest['last_name'] ?? '')) ?: 'NightsBridge Guest'),
            'guest_email' => (string)($booking['guest_email'] ?? $guest['email'] ?? ''),
            'guest_phone' => (string)($booking['guest_phone'] ?? $guest['phone'] ?? ''),
            'check_in' => (string)($booking['check_in'] ?? $booking['arrival'] ?? $booking['arrival_date'] ?? ''),
            'check_out' => (string)($booking['check_out'] ?? $booking['departure'] ?? $booking['departure_date'] ?? ''),
            'room_type_external_id' => (string)($booking['room_id'] ?? $booking['room_type_id'] ?? $booking['unit_id'] ?? ''),
            'rate_external_id' => (string)($booking['rate_id'] ?? $booking['rate_plan_id'] ?? ''),
            'rooms' => (int)($booking['rooms'] ?? $booking['room_count'] ?? 1),
            'adults' => (int)($booking['adults'] ?? 1),
            'children' => (int)($booking['children'] ?? 0),
            'total_amount' => (float)($booking['total_amount'] ?? $booking['amount'] ?? 0),
            'currency' => (string)($booking['currency'] ?? 'ZAR'),
            'status' => (string)($booking['status'] ?? 'confirmed'),
            'special_requests' => (string)($booking['special_requests'] ?? $booking['notes'] ?? ''),
            'raw_payload' => $booking,
        ];
    }
}

if (!function_exists('nb_push_availability')) {
    function nb_push_availability(array $connection, array $availabilityRows): array
    {
        $payload = nb_build_availability_payload($connection, $availabilityRows);

        /*
         * Endpoint must be confirmed by NightsBridge.
         * This uses a conventional placeholder route.
         */
        return nb_http_request($connection, 'POST', '/pms/availability', $payload);
    }
}

if (!function_exists('nb_push_rates')) {
    function nb_push_rates(array $connection, array $rateRows): array
    {
        $payload = nb_build_rates_payload($connection, $rateRows);

        /*
         * Endpoint must be confirmed by NightsBridge.
         * This uses a conventional placeholder route.
         */
        return nb_http_request($connection, 'POST', '/pms/rates', $payload);
    }
}

if (!function_exists('nb_pull_bookings')) {
    function nb_pull_bookings(array $connection, string $dateFrom, string $dateTo): array
    {
        if (!nb_live_enabled($connection)) {
            return [
                'ok' => false,
                'blocked' => true,
                'message' => 'NightsBridge live booking pull is disabled. Add NIGHTSBRIDGE_LIVE_ENABLED=1 to connection notes after approval.',
                'bookings' => [],
            ];
        }

        $endpoint = '/pms/bookings?property_id='
            . rawurlencode((string)($connection['external_property_id'] ?? ''))
            . '&date_from=' . rawurlencode($dateFrom)
            . '&date_to=' . rawurlencode($dateTo);

        $response = nb_http_request($connection, 'GET', $endpoint, []);

        $bookings = [];
        $json = $response['response_json'] ?? null;

        if (is_array($json)) {
            $items = $json['bookings'] ?? $json['reservations'] ?? $json['data'] ?? [];
            if (is_array($items)) {
                foreach ($items as $item) {
                    if (is_array($item)) {
                        $bookings[] = nb_normalize_booking($item);
                    }
                }
            }
        }

        return [
            'ok' => !empty($response['ok']),
            'blocked' => false,
            'message' => $response['message'] ?? '',
            'raw_response' => $response['response_body'] ?? '',
            'bookings' => $bookings,
        ];
    }
}
