<?php

declare(strict_types=1);

namespace BotGuard\Controllers\Admin;

use BotGuard\Core\Auth;
use BotGuard\Core\Controller;
use BotGuard\Core\Crypto;
use BotGuard\Core\Csrf;
use BotGuard\Core\Request;
use BotGuard\Core\Response;
use BotGuard\Core\Session;
use BotGuard\Core\View;
use BotGuard\Models\AuditLog;
use BotGuard\Models\Setting;
use BotGuard\Services\Mail\Mailer;

/**
 * Admin: SMTP / email settings. Lets the administrator configure outgoing mail
 * and send a test message to confirm delivery. The SMTP password is encrypted
 * at rest via Crypto and never rendered back to the browser.
 */
final class SettingsController extends Controller
{
    private const ENCRYPTIONS = ['tls', 'ssl', 'none'];

    public function __construct(
        View $view,
        Session $session,
        Csrf $csrf,
        Request $request,
        private Setting $settings,
        private Mailer $mailer,
        private AuditLog $audit,
        private Auth $auth,
    ) {
        parent::__construct($view, $session, $csrf, $request);
    }

    public function smtp(Request $request): Response
    {
        return $this->render('admin.smtp', [
            'title'        => 'SMTP & Email',
            'smtp'         => [
                'host'         => $this->settings->value('smtp_host', config('mail.host', '')),
                'port'         => $this->settings->value('smtp_port', config('mail.port', 587)),
                'encryption'   => $this->settings->value('smtp_encryption', config('mail.encryption', 'tls')),
                'username'     => $this->settings->value('smtp_username', config('mail.username', '')),
                'from_address' => $this->settings->value('smtp_from_address', config('mail.from_address', '')),
                'from_name'    => $this->settings->value('smtp_from_name', config('mail.from_name', config('app.name'))),
                'has_password' => $this->settings->value('smtp_password', '') !== '',
            ],
            'encryptions'  => self::ENCRYPTIONS,
            'configured'   => $this->mailer->isConfigured(),
        ]);
    }

    public function update(Request $request): Response
    {
        $validator = $this->validate([
            'smtp_host'         => 'required|maxlen:191',
            'smtp_port'         => 'required|integer|min:1|max:65535',
            'smtp_from_address' => 'required|email',
        ]);

        if ($validator->fails()) {
            return $this->redirect('/admin/smtp', 'error', $validator->firstError());
        }

        $encryption = (string) $request->input('smtp_encryption', 'tls');
        $encryption = in_array($encryption, self::ENCRYPTIONS, true) ? $encryption : 'tls';

        $this->settings->set('smtp_host', trim((string) $request->input('smtp_host')), 'string', 'smtp');
        $this->settings->set('smtp_port', (int) $request->input('smtp_port'), 'int', 'smtp');
        $this->settings->set('smtp_encryption', $encryption, 'string', 'smtp');
        $this->settings->set('smtp_username', trim((string) $request->input('smtp_username', '')), 'string', 'smtp');
        $this->settings->set('smtp_from_address', trim((string) $request->input('smtp_from_address')), 'string', 'smtp');
        $this->settings->set('smtp_from_name', trim((string) $request->input('smtp_from_name', '')), 'string', 'smtp');

        // Only overwrite the password when a new one was supplied (encrypted at rest).
        $password = (string) $request->input('smtp_password', '');
        if ($password !== '') {
            $this->settings->set('smtp_password', Crypto::encrypt($password), 'secret', 'smtp');
        }

        $this->audit->record($this->auth->id(), 'settings.smtp.updated', $request->ip(), [
            'host' => $request->input('smtp_host'),
        ]);

        return $this->redirect('/admin/smtp', 'success', 'SMTP settings saved.');
    }

    public function test(Request $request): Response
    {
        $to = trim((string) $request->input('test_email'));
        if (! filter_var($to, FILTER_VALIDATE_EMAIL)) {
            $to = (string) ($this->auth->user()['email'] ?? '');
        }

        if ($to === '') {
            return $this->redirect('/admin/smtp', 'error', 'Enter a valid recipient email for the test.');
        }

        $ok = $this->mailer->send($to, 'BotGuard SMTP test', 'test');

        if ($ok) {
            return $this->redirect('/admin/smtp', 'success', "Test email sent to {$to}.");
        }

        return $this->redirect('/admin/smtp', 'error', 'Test failed: ' . ($this->mailer->lastError() ?? 'unknown error'));
    }
}
