<?php
declare(strict_types=1);

namespace App\Modules\Settings;

use App\Core\Exceptions\IntegrationConfigException;
use App\Core\Http\RedirectPathResolver;
use App\Core\Http\Request;
use App\Core\Http\Response;
use App\Core\I18n\Translator;
use App\Core\Security\Csrf;
use App\Core\Support\Flash;
use App\Core\View\Template;
use App\Modules\Auth\AuthService;
use Throwable;

final class SmsplanetIntegrationController
{
    private const MAX_SMS_LENGTH = 918;

    public function __construct(
        private readonly Template $template,
        private readonly Translator $translator,
        private readonly AuthService $auth,
        private readonly SmsplanetIntegrationRepository $repository,
        private readonly SmsplanetApiClient $apiClient,
        private readonly IntegrationsRepository $integrations
    ) {
    }

    public function index(Request $request): Response
    {
        $html = $this->template->render('settings/smsplanet', [
            'title' => $this->translator->get('settings.smsplanet.title'),
            'activeMenu' => 'settings',
            'activeSettings' => 'integrations',
            'user' => $this->auth->user(),
            'csrfToken' => Csrf::token(),
            'settings' => $this->repository->getSettings(),
            'errorMessage' => (string) Flash::get('settings_error', ''),
            'successMessage' => (string) Flash::get('settings_success', ''),
            'testMessage' => (string) Flash::get('smsplanet_test', ''),
        ], 'layouts/app');

        return Response::html($html);
    }

    public function save(Request $request): Response
    {
        $redirectTo = $this->resolveRedirect($request);
        if (!Csrf::validate((string) $request->input('_token', ''))) {
            Flash::set('settings_error', $this->translator->get('auth.errors.csrf_expired'));
            return Response::redirect($redirectTo);
        }

        try {
            $this->repository->saveSettings([
                'auth_method' => (string) $request->input('auth_method', ''),
                'api_token' => (string) $request->input('api_token', ''),
                'api_key' => (string) $request->input('api_key', ''),
                'api_password' => (string) $request->input('api_password', ''),
                'sender' => (string) $request->input('sender', ''),
                'sender_mode' => (string) $request->input('sender_mode', ''),
                'sender_phone' => (string) $request->input('sender_phone', ''),
                'default_footer' => (string) $request->input('default_footer', ''),
                'clear_polish' => $request->input('clear_polish', ''),
                'transactional' => $request->input('transactional', ''),
                'is_active' => $request->input('is_active', ''),
            ]);
            Flash::set('settings_success', $this->translator->get('settings.smsplanet.flash.saved'));
        } catch (Throwable $exception) {
            Flash::set(
                'settings_error',
                $this->translator->get('settings.smsplanet.flash.save_failed') . ' ' . $exception->getMessage()
            );
        }

        return Response::redirect($redirectTo);
    }

    public function test(Request $request): Response
    {
        $redirectTo = $this->resolveRedirect($request);
        if (!Csrf::validate((string) $request->input('_token', ''))) {
            Flash::set('settings_error', $this->translator->get('auth.errors.csrf_expired'));
            return Response::redirect($redirectTo);
        }

        try {
            $phone = $this->validatePhone((string) $request->input('phone', ''));
            $message = $this->validateMessage((string) $request->input('message', ''));
            $credentials = $this->repository->getCredentials();
            if ($credentials === null) {
                throw new IntegrationConfigException('Najpierw zapisz kompletna i aktywna konfiguracje SMSPLANET.');
            }

            $finalMessage = $this->buildFinalMessage($message, (string) ($credentials['default_footer'] ?? ''));
            $this->validateFinalMessageLength($finalMessage);

            $result = $this->apiClient->sendSms($credentials, $phone, $finalMessage);
            $this->integrations->updateTestResult(
                $credentials['integration_id'],
                $result['ok'] ? 'ok' : 'fail',
                (int) $result['http_code'],
                (string) $result['message']
            );

            if ($result['ok']) {
                Flash::set('smsplanet_test', $this->translator->get('settings.smsplanet.flash.test_success', [
                    'message_id' => (string) $result['message_id'],
                ]));
            } else {
                Flash::set('settings_error', $this->translator->get('settings.smsplanet.flash.test_failed') . ' ' . $result['message']);
            }
        } catch (Throwable $exception) {
            Flash::set('settings_error', $this->translator->get('settings.smsplanet.flash.test_failed') . ' ' . $exception->getMessage());
        }

        return Response::redirect($redirectTo);
    }

    private function resolveRedirect(Request $request): string
    {
        return RedirectPathResolver::resolve(
            (string) $request->input('return_to', '/settings/integrations/smsplanet'),
            ['/settings/integrations'],
            '/settings/integrations/smsplanet'
        );
    }

    private function validatePhone(string $value): string
    {
        $phone = preg_replace('/[\s+\-()]/', '', trim($value)) ?? '';
        if (preg_match('/^\d{8,15}$/', $phone) !== 1) {
            throw new IntegrationConfigException('Podaj numer telefonu w formacie 600111222 albo 48600111222.');
        }

        return $phone;
    }

    private function validateMessage(string $value): string
    {
        $message = trim($value);
        if ($message === '') {
            throw new IntegrationConfigException('Podaj tresc testowego SMS.');
        }
        if ($this->messageLength($message) > self::MAX_SMS_LENGTH) {
            throw new IntegrationConfigException('Tresc testowego SMS nie moze przekraczac 918 znakow.');
        }

        return $message;
    }

    private function buildFinalMessage(string $message, string $defaultFooter): string
    {
        $footer = trim(str_replace(["\r\n", "\r"], "\n", $defaultFooter));
        if ($footer === '') {
            return $message;
        }

        return rtrim($message) . "\n\n" . $footer;
    }

    private function validateFinalMessageLength(string $message): void
    {
        if ($this->messageLength($message) > self::MAX_SMS_LENGTH) {
            throw new IntegrationConfigException('Tresc testowego SMS ze stopka nie moze przekraczac 918 znakow.');
        }
    }

    private function messageLength(string $value): int
    {
        if (function_exists('mb_strlen')) {
            return mb_strlen($value, 'UTF-8');
        }

        return strlen($value);
    }
}
