<?php

declare(strict_types=1);

require_once __DIR__ . '/helpers.php';

class ApiException extends Exception
{
    public function __construct(
        string $message,
        public int $statusCode = 500,
        public ?array $response = null
    ) {
        parent::__construct($message, $statusCode);
    }
}

function api_encode_json(array $body): string
{
    $json = json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    if ($json === false) {
        throw new ApiException('Could not encode API JSON body: ' . json_last_error_msg(), 500);
    }

    return $json;
}

function api_store_last_request_debug(array $debug): void
{
    $GLOBALS['karvi_api_last_request_debug'] = $debug;
}

function api_get_last_request_debug(): ?array
{
    $debug = $GLOBALS['karvi_api_last_request_debug'] ?? null;

    return is_array($debug) ? $debug : null;
}

function api_config(): array
{
    static $config = null;
    if ($config === null) {
        $config = require __DIR__ . '/../config/api.php';
    }
    return $config;
}

function api_is_configured(): bool
{
    $config = api_config();

    if (empty($config['enabled'])) {
        return false;
    }

    $baseUrl = trim((string)($config['base_url'] ?? ''));

    return $baseUrl !== '' && $baseUrl !== 'https://your-api-domain.com';
}

function api_show_local_store_notice(): bool
{
    return (bool)(api_config()['show_local_store_notice'] ?? false);
}

function api_customer_api_enabled(): bool
{
    return api_is_configured() || api_auth_enabled();
}

function api_feature_enabled(string $feature): bool
{
    $customer = api_config()['customer'] ?? null;
    if (!is_array($customer) || $customer === []) {
        return api_customer_api_enabled();
    }

    return !empty($customer[$feature]);
}

function api_local_login_fallback_enabled(): bool
{
    return !empty(api_config()['local_login_fallback']);
}

function api_can_use_partner_api(): bool
{
    return api_auth_enabled() && api_partner_session_active();
}

function api_partner_session_active(): bool
{
    return api_auth_enabled() && api_bearer_token() !== null;
}

function api_should_sync_remotely(): bool
{
    return api_partner_session_active();
}

function api_resolve_bearer_token(): ?string
{
    $sessionToken = api_bearer_token();
    if ($sessionToken !== null) {
        return $sessionToken;
    }

    $config = api_config();
    $apiKey = trim((string)($config['api_key'] ?? ''));

    return $apiKey !== '' ? $apiKey : null;
}

function api_auth_enabled(): bool
{
    $config = api_config();

    if (empty($config['auth_enabled'])) {
        return false;
    }

    $baseUrl = trim((string)($config['base_url'] ?? ''));

    return $baseUrl !== '' && $baseUrl !== 'https://your-api-domain.com';
}

function api_request_datetime(): string
{
    require_once __DIR__ . '/mvc.php';

    return \App\Services\ApiService::requestDatetime();
}

function api_auth_login(string $email, string $password): array
{
    if (!api_auth_enabled()) {
        return [
            'success' => false,
            'message' => 'Login API is not configured.',
            'data' => null,
        ];
    }

    require_once __DIR__ . '/mvc.php';

    $response = \App\Services\ApiService::instance()->login($email, $password);

    if (!$response['success'] || !is_array($response['data'])) {
        return [
            'success' => false,
            'message' => (string)($response['message'] ?? 'Login failed.'),
            'data' => $response['data'],
        ];
    }

    if (empty($response['data']['token'])) {
        return [
            'success' => false,
            'message' => 'Login API did not return an access token.',
            'data' => $response['data'],
        ];
    }

    return [
        'success' => true,
        'message' => (string)($response['data']['message'] ?? 'Login successful.'),
        'data' => $response['data'],
    ];
}

function api_bearer_token(): ?string
{
    if (!function_exists('auth_api_token')) {
        return null;
    }

    return auth_api_token();
}

function api_build_url(string $endpointKey, array $params = []): string
{
    $config = api_config();
    $path = $config['endpoints'][$endpointKey] ?? '';

    foreach ($params as $key => $value) {
        $path = str_replace('{' . $key . '}', rawurlencode((string)$value), $path);
    }

    return rtrim($config['base_url'], '/') . $path;
}

function api_endpoint_requires_auth(string $endpointKey): bool
{
    static $public = [
        'contract_sign' => true,
    ];

    return empty($public[$endpointKey]);
}

function api_curl_available(): bool
{
    return function_exists('curl_init');
}

function api_execute_request(string $method, string $endpointKey, array $params = [], ?array $body = null, ?bool $withAuth = null): array
{
    if (!api_curl_available()) {
        throw new ApiException('PHP cURL extension is not enabled on this server.', 503);
    }

    require_once __DIR__ . '/mvc.php';

    $config = api_config();
    $path = $config['endpoints'][$endpointKey] ?? '';

    foreach ($params as $key => $value) {
        $path = str_replace('{' . $key . '}', rawurlencode((string)$value), $path);
    }

    $withAuth = $withAuth ?? api_endpoint_requires_auth($endpointKey);

    api_store_last_request_debug([
        'url' => rtrim($config['base_url'], '/') . $path,
        'method' => strtoupper($method),
        'request_body' => $body,
        'request_json' => $body !== null ? api_encode_json($body) : '',
        'http_status' => null,
        'response_raw' => null,
        'response_decoded' => null,
        'curl_error' => null,
    ]);

    $response = \App\Services\ApiService::instance()->request(
        strtoupper($method),
        $path,
        $body,
        $withAuth
    );

    api_store_last_request_debug(array_merge(api_get_last_request_debug() ?? [], [
        'http_status' => $response['http_status'],
        'response_raw' => $response['raw'] ?? null,
        'curl_error' => null,
    ]));

    if (!$response['success']) {
        $decoded = is_array($response['data']) ? $response['data'] : null;
        api_store_last_request_debug(array_merge(api_get_last_request_debug() ?? [], [
            'response_decoded' => $decoded,
        ]));

        throw new ApiException(
            (string)$response['message'],
            max(400, (int)$response['http_status']),
            $decoded
        );
    }

    $decoded = is_array($response['data']) ? $response['data'] : [];
    api_store_last_request_debug(array_merge(api_get_last_request_debug() ?? [], [
        'response_decoded' => $decoded,
    ]));

    return $decoded;
}

function api_partner_request(string $method, string $endpointKey, array $params = [], ?array $body = null): array
{
    if (!api_auth_enabled()) {
        throw new ApiException('Partner API is not configured.', 503);
    }

    $token = api_bearer_token() ?? api_resolve_bearer_token();
    if ($token === null) {
        throw new ApiException('Not authenticated.', 401);
    }

    return api_execute_request($method, $endpointKey, $params, $body);
}

function api_request(string $method, string $endpointKey, array $params = [], ?array $body = null): array
{
    if (!api_is_configured()) {
        throw new ApiException(
            'External API is not configured. Update config/api.php with your API base URL and endpoints.',
            503
        );
    }

    return api_execute_request($method, $endpointKey, $params, $body);
}

function api_get(string $endpointKey, array $params = []): array
{
    return api_request('GET', $endpointKey, $params);
}

function api_partner_get(string $endpointKey, array $params = []): array
{
    return api_partner_request('GET', $endpointKey, $params);
}

function api_partner_post(string $endpointKey, array $params = [], array $body = []): array
{
    return api_partner_request('POST', $endpointKey, $params, $body);
}

function api_public_post(string $endpointKey, array $params = [], array $body = []): array
{
    if (!api_customer_api_enabled()) {
        throw new ApiException('Customer API is not configured.', 503);
    }

    return api_execute_request('POST', $endpointKey, $params, $body);
}

function api_public_get(string $endpointKey, array $params = []): array
{
    if (!api_customer_api_enabled()) {
        throw new ApiException('Customer API is not configured.', 503);
    }

    return api_execute_request('GET', $endpointKey, $params);
}

function api_public_put(string $endpointKey, array $params = [], array $body = []): array
{
    if (!api_customer_api_enabled()) {
        throw new ApiException('Customer API is not configured.', 503);
    }

    return api_execute_request('PUT', $endpointKey, $params, $body);
}

function api_public_patch(string $endpointKey, array $params = [], array $body = []): array
{
    if (!api_customer_api_enabled()) {
        throw new ApiException('Customer API is not configured.', 503);
    }

    return api_execute_request('PATCH', $endpointKey, $params, $body);
}

function api_partner_delete(string $endpointKey, array $params = []): array
{
    return api_partner_request('DELETE', $endpointKey, $params);
}

function api_post(string $endpointKey, array $params = [], array $body = []): array
{
    return api_request('POST', $endpointKey, $params, $body);
}

function api_put(string $endpointKey, array $params = [], array $body = []): array
{
    return api_request('PUT', $endpointKey, $params, $body);
}

function api_patch(string $endpointKey, array $params = [], array $body = []): array
{
    return api_request('PATCH', $endpointKey, $params, $body);
}

function api_extract_data(array $response, string $key = 'data'): array
{
    if (isset($response[$key]) && is_array($response[$key])) {
        return $response[$key];
    }
    return $response;
}

function api_extract_list(array $response, string $key = 'data'): array
{
    if (isset($response['contracts']) && is_array($response['contracts'])) {
        return $response['contracts'];
    }

    $data = api_extract_data($response, $key);
    if (isset($data['contracts']) && is_array($data['contracts'])) {
        return $data['contracts'];
    }
    if (array_is_list($data)) {
        return $data;
    }
    return [];
}

function api_extract_item(array $response, string $key = 'data'): ?array
{
    $data = api_extract_data($response, $key);
    if (isset($data['contract']) && is_array($data['contract'])) {
        return $data['contract'];
    }
    if (!empty($data['token']) || !empty($data['sign_token']) || !empty($data['id'])) {
        return $data;
    }
    return null;
}

function api_error_message(Throwable $e): string
{
    if ($e instanceof ApiException) {
        return $e->getMessage();
    }

    return admin_exception_message($e);
}

function admin_exception_message(Throwable $e): string
{
    if ($e instanceof ApiException) {
        return $e->getMessage();
    }

    $message = trim($e->getMessage());
    if ($message === '') {
        return 'An unexpected error occurred. Please try again.';
    }

    return $message;
}

function admin_create_environment_check(): ?string
{
    $config = app_config();
    $paths = [
        'database' => dirname($config['local_db']),
        'uploads/contracts' => $config['contracts_dir'],
        'uploads/signatures' => $config['signatures_dir'],
        'uploads/signed' => $config['signed_dir'],
    ];

    foreach ($paths as $label => $path) {
        if (!is_dir($path) && !@mkdir($path, 0755, true) && !is_dir($path)) {
            return __('flash_error_dir_create', ['dir' => $label]);
        }

        if (!is_writable($path)) {
            return __('flash_error_dir_writable', ['dir' => $label]);
        }
    }

    require_once __DIR__ . '/vendor_loader.php';
    $vendorDir = karvi_resolve_vendor_dir();
    if (!is_file($vendorDir . '/setasign/fpdf/fpdf.php')) {
        return __('flash_error_vendor_missing');
    }

    return null;
}
