<?php
declare(strict_types=1);

namespace App\Modules\Settings;

use App\Core\Exceptions\IntegrationConfigException;
use App\Core\Support\StringHelper;
use PDO;
use Throwable;

final class HostedSmsIntegrationRepository
{
    private const INTEGRATION_TYPE = 'hostedsms';
    private const INTEGRATION_NAME = 'HostedSMS';
    private const INTEGRATION_BASE_URL = 'https://api.hostedsms.pl/SimpleApi';

    private readonly IntegrationsRepository $integrations;
    private readonly IntegrationSecretCipher $cipher;

    public function __construct(
        private readonly PDO $pdo,
        private readonly string $secret
    ) {
        $this->integrations = new IntegrationsRepository($this->pdo);
        $this->cipher = new IntegrationSecretCipher($this->secret);
    }

    /**
     * @return array<string, mixed>
     */
    public function getSettings(): array
    {
        $this->ensureRow();
        $integrationId = $this->ensureBaseIntegration();
        $row = $this->fetchRow();
        $integration = $this->integrations->findById($integrationId);
        $passwordEncrypted = $this->resolvePasswordEncrypted($row, $integration);

        return [
            'integration_id' => $integrationId,
            'user_email' => trim((string) ($row['user_email'] ?? '')),
            'sender' => trim((string) ($row['sender'] ?? '')),
            'convert_message_to_gsm7' => !empty($row['convert_message_to_gsm7']),
            'has_password' => $passwordEncrypted !== null && $passwordEncrypted !== '',
            'is_active' => (int) ($integration['is_active'] ?? 1) === 1,
            'last_test_status' => trim((string) ($integration['last_test_status'] ?? '')),
            'last_test_http_code' => isset($integration['last_test_http_code']) ? (int) $integration['last_test_http_code'] : null,
            'last_test_message' => trim((string) ($integration['last_test_message'] ?? '')),
            'last_test_at' => trim((string) ($integration['last_test_at'] ?? '')),
            'updated_at' => trim((string) ($row['updated_at'] ?? '')),
        ];
    }

    /**
     * @param array<string, mixed> $payload
     */
    public function saveSettings(array $payload): void
    {
        $this->ensureRow();
        $integrationId = $this->ensureBaseIntegration();
        $row = $this->fetchRow();
        if ($row === null) {
            throw new IntegrationConfigException('Brak rekordu konfiguracji HostedSMS.');
        }

        $userEmail = trim((string) ($payload['user_email'] ?? ''));
        if (!filter_var($userEmail, FILTER_VALIDATE_EMAIL)) {
            throw new IntegrationConfigException('Podaj poprawny login e-mail HostedSMS.');
        }

        $sender = trim((string) ($payload['sender'] ?? ''));
        if ($sender === '' || strlen($sender) > 32) {
            throw new IntegrationConfigException('Podaj nadpis Sender HostedSMS (maks. 32 znaki).');
        }

        $currentEncrypted = $this->resolvePasswordEncrypted($row, $this->integrations->findById($integrationId));
        $password = trim((string) ($payload['password'] ?? ''));
        $nextEncrypted = $currentEncrypted;
        if ($password !== '') {
            $nextEncrypted = $this->cipher->encrypt($password);
        }

        if ($nextEncrypted === null || $nextEncrypted === '') {
            throw new IntegrationConfigException('Podaj haslo HostedSMS.');
        }

        $statement = $this->pdo->prepare(
            'UPDATE hostedsms_integration_settings
             SET user_email = :user_email,
                 password_encrypted = :password_encrypted,
                 sender = :sender,
                 convert_message_to_gsm7 = :convert_message_to_gsm7,
                 updated_at = NOW()
             WHERE id = 1'
        );
        $statement->execute([
            'user_email' => $userEmail,
            'password_encrypted' => $nextEncrypted,
            'sender' => $sender,
            'convert_message_to_gsm7' => !empty($payload['convert_message_to_gsm7']) ? 1 : 0,
        ]);

        $this->updateIntegrationActive($integrationId, !empty($payload['is_active']));
        $this->integrations->updateApiKeyEncrypted($integrationId, $nextEncrypted);
    }

    /**
     * @return array{integration_id: int, user_email: string, password: string, sender: string, convert_message_to_gsm7: bool}|null
     */
    public function getCredentials(): ?array
    {
        $this->ensureRow();
        $integrationId = $this->ensureBaseIntegration();
        $row = $this->fetchRow();
        if ($row === null) {
            return null;
        }

        $userEmail = trim((string) ($row['user_email'] ?? ''));
        $sender = trim((string) ($row['sender'] ?? ''));
        $encrypted = $this->resolvePasswordEncrypted($row, $this->integrations->findById($integrationId));

        if ($userEmail === '' || $sender === '' || $encrypted === null || $encrypted === '') {
            return null;
        }

        $password = trim($this->cipher->decrypt($encrypted));
        if ($password === '') {
            return null;
        }

        return [
            'integration_id' => $integrationId,
            'user_email' => $userEmail,
            'password' => $password,
            'sender' => $sender,
            'convert_message_to_gsm7' => !empty($row['convert_message_to_gsm7']),
        ];
    }

    private function ensureBaseIntegration(): int
    {
        return $this->integrations->ensureIntegration(
            self::INTEGRATION_TYPE,
            self::INTEGRATION_NAME,
            self::INTEGRATION_BASE_URL,
            15,
            true
        );
    }

    private function ensureRow(): void
    {
        $integrationId = $this->ensureBaseIntegration();
        $statement = $this->pdo->prepare(
            'INSERT INTO hostedsms_integration_settings (id, integration_id, created_at, updated_at)
             VALUES (1, :integration_id, NOW(), NOW())
             ON DUPLICATE KEY UPDATE integration_id = VALUES(integration_id), updated_at = VALUES(updated_at)'
        );
        $statement->execute(['integration_id' => $integrationId]);
    }

    /**
     * @return array<string, mixed>|null
     */
    private function fetchRow(): ?array
    {
        try {
            $statement = $this->pdo->prepare('SELECT * FROM hostedsms_integration_settings WHERE id = 1 LIMIT 1');
            $statement->execute();
            $row = $statement->fetch(PDO::FETCH_ASSOC);
        } catch (Throwable) {
            return null;
        }

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

    /**
     * @param array<string, mixed>|null $row
     * @param array<string, mixed>|null $integration
     */
    private function resolvePasswordEncrypted(?array $row, ?array $integration): ?string
    {
        $settingsValue = trim((string) ($row['password_encrypted'] ?? ''));
        if ($settingsValue !== '') {
            return $settingsValue;
        }

        $baseValue = trim((string) ($integration['api_key_encrypted'] ?? ''));
        return StringHelper::nullableString($baseValue);
    }

    private function updateIntegrationActive(int $integrationId, bool $isActive): void
    {
        $statement = $this->pdo->prepare(
            'UPDATE integrations
             SET is_active = :is_active,
                 updated_at = NOW()
             WHERE id = :id AND type = :type'
        );
        $statement->execute([
            'id' => $integrationId,
            'type' => self::INTEGRATION_TYPE,
            'is_active' => $isActive ? 1 : 0,
        ]);
    }
}
