<?php

namespace Chatbeep\PhpSdk;

use RuntimeException;

class ChatbeepClient
{
    public function __construct(
        private readonly string $apiBase,
        private readonly ?string $bearerToken = null,
    ) {}

    public function health(): array
    {
        return $this->request('GET', '/health');
    }

    public function widgetConfig(string $installationToken): array
    {
        return $this->request('GET', '/widget/config/'.$installationToken);
    }

    public function widgetInstallationHealth(string $installationToken, ?string $currentUrl = null): array
    {
        $path = '/widget/installations/'.$installationToken.'/health';

        if ($currentUrl) {
            $path .= '?current_url='.rawurlencode($currentUrl);
        }

        return $this->request('GET', $path);
    }

    public function installationHealth(string $installationToken, ?string $currentUrl = null): array
    {
        return $this->widgetInstallationHealth($installationToken, $currentUrl);
    }

    public function widgetPing(array $payload): array
    {
        return $this->request('POST', '/widget/ping', $payload);
    }

    public function upsertWidgetVisitor(array $payload): array
    {
        return $this->request('POST', '/widget/visitors', $payload);
    }

    public function createWidgetConversation(array $payload): array
    {
        return $this->request('POST', '/widget/conversations', $payload);
    }

    public function createConversation(array $payload): array
    {
        return $this->createWidgetConversation($payload);
    }

    public function getWidgetConversationMessages(string $conversation, string $widgetToken, array $query = []): array
    {
        $query = array_merge(['token' => $widgetToken], $query);

        return $this->request('GET', '/widget/conversations/'.$conversation.'/messages', query: $query);
    }

    public function sendWidgetConversationMessage(string $conversation, array $payload): array
    {
        return $this->request('POST', '/widget/conversations/'.$conversation.'/messages', body: $payload);
    }

    public function startWidgetVerification(string $conversation, array $payload): array
    {
        return $this->request('POST', '/widget/conversations/'.$conversation.'/verification/start', body: $payload);
    }

    public function confirmWidgetVerification(string $conversation, array $payload): array
    {
        return $this->request('POST', '/widget/conversations/'.$conversation.'/verification/confirm', body: $payload);
    }

    public function mobileLogin(string $email, string $password, string $deviceName): array
    {
        return $this->request('POST', '/mobile/login', body: [
            'email' => $email,
            'password' => $password,
            'device_name' => $deviceName,
        ]);
    }

    public function mobileMe(): array
    {
        return $this->request('GET', '/mobile/me', auth: true);
    }

    public function mobileConversations(array $query = []): array
    {
        return $this->request('GET', '/mobile/conversations', query: $query, auth: true);
    }

    public function mobileConversation(int|string $conversation): array
    {
        return $this->request('GET', '/mobile/conversations/'.$conversation, auth: true);
    }

    public function sendMobileConversationMessage(int|string $conversation, array $payload): array
    {
        return $this->request('POST', '/mobile/conversations/'.$conversation.'/messages', body: $payload, auth: true);
    }

    public function assignMobileConversation(int|string $conversation, array $payload): array
    {
        return $this->request('POST', '/mobile/conversations/'.$conversation.'/assign', body: $payload, auth: true);
    }

    public function transferMobileConversation(int|string $conversation, array $payload): array
    {
        return $this->request('POST', '/mobile/conversations/'.$conversation.'/transfer', body: $payload, auth: true);
    }

    public function closeMobileConversation(int|string $conversation, array $payload = []): array
    {
        return $this->request('POST', '/mobile/conversations/'.$conversation.'/close', body: $payload, auth: true);
    }

    /**
     * @param  array<string, mixed>  $body
     * @param  array<string, mixed>  $query
     */
    private function request(
        string $method,
        string $path,
        array $body = [],
        array $query = [],
        bool $auth = false,
    ): array
    {
        $headers = ['Accept: application/json'];

        if ($auth) {
            if (! $this->bearerToken) {
                throw new RuntimeException('Bearer token is required for this call.');
            }

            $headers[] = 'Authorization: Bearer '.$this->bearerToken;
        }

        $content = null;

        if ($body !== []) {
            $headers[] = 'Content-Type: application/json';
            $content = json_encode($body, JSON_THROW_ON_ERROR);
        }

        if ($query !== []) {
            $path .= '?'.http_build_query($query);
        }

        $context = stream_context_create([
            'http' => [
                'method' => $method,
                'header' => implode("\r\n", $headers),
                'content' => $content,
                'ignore_errors' => true,
            ],
        ]);

        $response = file_get_contents(rtrim($this->apiBase, '/').$path, false, $context);

        if ($response === false) {
            throw new RuntimeException('Chatbeep request failed.');
        }

        return json_decode($response, true, 512, JSON_THROW_ON_ERROR);
    }
}
