<?php

namespace Tests\Feature;

use App\Enums\EmailStatus;
use App\Enums\EmailTemplateCategory;
use App\Models\EmailConfiguration;
use App\Models\EmailMessage;
use App\Models\EmailTemplate;
use App\Models\Invoice;
use App\Models\User;
use App\Services\Email\EmailConfigurationService;
use App\Services\Email\EmailPlaceholderService;
use App\Services\Email\EmailSanitizer;
use App\Services\Email\EmailSenderService;
use App\Services\Email\EmailTemplateService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;

class EmailSystemTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed(\Database\Seeders\RolesAndPermissionsSeeder::class);
        $this->seed(\Database\Seeders\EmailTemplateSeeder::class);
    }

    public function test_email_settings_page_loads_for_administrator(): void
    {
        $user = User::factory()->create();
        $user->assignRole('Administrator');

        $this->actingAs($user)
            ->get(route('system.settings.index', ['tab' => 'email']))
            ->assertOk()
            ->assertSee('Email Configuration');
    }

    public function test_administrator_can_save_email_configuration_without_exposing_password(): void
    {
        $user = User::factory()->create();
        $user->assignRole('Administrator');

        $response = $this->actingAs($user)->put(route('system.email-settings.update'), [
            'provider' => 'smtp',
            'encryption' => 'tls',
            'smtp_host' => 'smtp.example.com',
            'smtp_port' => 587,
            'smtp_username' => 'mailer',
            'smtp_password' => 'secret-pass',
            'from_name' => 'Southend School',
            'from_address' => 'billing@southend.edu',
            'is_enabled' => '1',
            'automated_enabled' => '1',
        ]);

        $response->assertRedirect(route('system.settings.index'));

        $config = EmailConfiguration::query()->first();
        $this->assertNotNull($config);
        $this->assertTrue($config->hasPassword());
        $this->assertSame('secret-pass', $config->smtp_password);

        $public = app(EmailConfigurationService::class)->toPublicArray($config);
        $this->assertArrayNotHasKey('smtp_password', $public);
        $this->assertTrue($public['has_password']);
    }

    public function test_placeholder_replacement_handles_missing_values(): void
    {
        $service = app(EmailPlaceholderService::class);

        $result = $service->replace('Hello {{client_name}}, ref {{missing_key}}', [
            'client_name' => 'Jane',
        ]);

        $this->assertSame('Hello Jane, ref ', $result);
    }

    public function test_sanitizer_strips_script_tags(): void
    {
        $clean = app(EmailSanitizer::class)->clean('<p>Hi</p><script>alert(1)</script>');

        $this->assertStringContainsString('<p>Hi</p>', $clean);
        $this->assertStringNotContainsString('script', $clean);
    }

    public function test_compose_email_queues_message(): void
    {
        Queue::fake();

        $user = User::factory()->create();
        $user->assignRole('Administrator');

        EmailConfiguration::query()->first()->update([
            'is_enabled' => true,
            'from_address' => 'test@southend.edu',
            'from_name' => 'Test',
            'smtp_host' => '127.0.0.1',
            'smtp_port' => 2525,
        ]);

        $response = $this->actingAs($user)->post(route('communication.emails.store'), [
            'to' => 'parent@example.com',
            'subject' => 'Test Subject',
            'body_html' => '<p>Hello parent</p>',
        ]);

        $response->assertRedirect();

        $this->assertDatabaseHas('email_messages', [
            'to' => 'parent@example.com',
            'subject' => 'Test Subject',
            'status' => EmailStatus::Queued->value,
        ]);
    }

    public function test_default_invoice_template_exists(): void
    {
        $template = app(EmailTemplateService::class)->defaultForCategory(EmailTemplateCategory::Invoice->value);

        $this->assertNotNull($template);
        $this->assertStringContainsString('{{invoice_number}}', $template->subject);
    }

    public function test_failed_email_can_be_retried(): void
    {
        Queue::fake();

        $user = User::factory()->create();
        $user->assignRole('Administrator');

        EmailConfiguration::query()->first()->update([
            'is_enabled' => true,
            'from_address' => 'test@southend.edu',
            'smtp_host' => '127.0.0.1',
            'smtp_port' => 2525,
        ]);

        $message = EmailMessage::query()->create([
            'status' => EmailStatus::Failed,
            'user_id' => $user->id,
            'from_address' => 'test@southend.edu',
            'to' => 'fail@example.com',
            'subject' => 'Retry me',
            'body_html' => '<p>Test</p>',
            'error_message' => 'SMTP timeout',
        ]);

        $this->actingAs($user)
            ->post(route('communication.emails.retry', $message))
            ->assertRedirect();

        $this->assertSame(EmailStatus::Queued, $message->fresh()->status);
    }

    public function test_email_center_requires_communications_permission(): void
    {
        $user = User::factory()->create();
        $user->assignRole('Teacher');

        $this->actingAs($user)
            ->get(route('communication.emails.index'))
            ->assertOk();
    }
}
