<?php

namespace EasyLinkAutomations\Auth\Platforms;

if (!defined('ABSPATH')) {
    exit;
}

use EasyLinkAutomations\Auth\AuthType;
use EasyLinkAutomations\Auth\Contracts\PlatformAuthInterface;

/**
 * Sendy API-key authentication for a self-hosted Sendy installation.
 *
 * Sendy takes its API key as an `api_key` POST body parameter rather than an
 * HTTP header, so authenticate() intentionally contributes no headers and
 * SendyRequestHelper reads the stored credentials directly instead.
 *
 * Test endpoint: {url}/api/brands/get-brands.php
 */
final class SendyAuth implements PlatformAuthInterface
{
    /**
     * Plain-text bodies Sendy returns when it rejects the credentials.
     */
    private const AUTH_ERRORS = [
        'no data passed'     => 'Sendy rejected the request. Check that the installation URL points at your Sendy install.',
        'api key not passed' => 'No API key reached Sendy.',
        'invalid api key'    => 'Sendy rejected the API key.',
    ];

    public static function getSlug(): string
    {
        return 'sendy';
    }

    public static function getName(): string
    {
        return 'Sendy';
    }

    public static function getAuthType(): string
    {
        return AuthType::API_KEY;
    }

    public static function getFields(): array
    {
        return [
            'url' => [
                'label'       => 'Sendy Installation URL',
                'type'        => 'text',
                'required'    => true,
                'placeholder' => 'https://send.example.com',
                'description' => 'Base URL of your self-hosted Sendy installation, without a trailing slash.',
            ],
            'api_key' => [
                'label'       => 'API Key',
                'type'        => 'text',
                'required'    => true,
                'password'    => true,
                'placeholder' => 'Your Sendy API key',
                'description' => 'Found in your Sendy dashboard under Settings.',
            ],
        ];
    }

    public static function getTestRequest(): ?array
    {
        return [
            'url'     => '{url}/api/brands/get-brands.php',
            'method'  => 'POST',
            'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
            'body'    => 'api_key={api_key}',
        ];
    }

    /**
     * Sendy authenticates through the request body, so there are no headers.
     */
    public static function authenticate(array $credentials): array
    {
        unset($credentials);

        return [];
    }

    /**
     * Decide the test outcome from the response body.
     *
     * Sendy answers virtually everything with HTTP 200 and reports failures as
     * plain text, so the generic 2xx check would accept an invalid API key.
     * CredentialTester calls this when a connector defines it.
     *
     * @return array{success: bool, message: string}|null Null to fall back to generic handling
     */
    public static function validateTestResponse(int $statusCode, string $rawBody): ?array
    {
        $body = trim($rawBody);

        if ($statusCode < 200 || $statusCode >= 300) {
            return [
                'success' => false,
                'message' => 'Sendy returned HTTP ' . $statusCode . '. Check that the installation URL points at your Sendy install.',
            ];
        }

        $needle = strtolower($body);
        if (isset(self::AUTH_ERRORS[$needle])) {
            return [
                'success' => false,
                'message' => 'Authentication failed: ' . self::AUTH_ERRORS[$needle],
            ];
        }

        // A valid key on an account without brands still proves the credentials work.
        if ($needle === 'no brands found') {
            return [
                'success' => true,
                'message' => 'Connection successful — this Sendy account has no brands yet',
            ];
        }

        if (is_array(json_decode($body, true))) {
            return ['success' => true, 'message' => 'Connection successful'];
        }

        return [
            'success' => false,
            'message' => 'Unexpected Sendy response: ' . ($body === '' ? 'empty body' : self::truncate($body)),
        ];
    }

    public static function toArray(): array
    {
        return [
            'slug'      => self::getSlug(),
            'name'      => self::getName(),
            'auth_type' => self::getAuthType(),
            'fields'    => self::getFields(),
        ];
    }

    private static function truncate(string $value): string
    {
        return strlen($value) > 120 ? substr($value, 0, 120) . '…' : $value;
    }
}
