<?php

namespace Tests\Feature\Integration;

use App\Domains\Attachable\Enums\AttachmentType;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Integration\Models\ClientIntegration;
use App\Domains\Integration\Models\Integration;
use App\Domains\Integration\Services\ClientIntegrationService;
use App\Domains\Integration\Services\MailService;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailer;
use Illuminate\Mail\MailManager;
use Illuminate\Support\Facades\Mail;
use Mockery;
use Tests\TestCase;

class MailServiceTest extends TestCase
{
    use RefreshDatabase;

    public function test_it_builds_an_isolated_smtp_mailer_from_the_client_integration(): void
    {
        $tenant = $this->createTenant();
        $this->createEmailIntegration();
        ClientIntegration::create([
            'client_id' => $tenant->client_id,
            'integration_code' => 'email',
            'integration_data' => $this->emailData(),
        ]);

        $mailer = Mockery::mock(Mailer::class);
        $mailer->shouldReceive('alwaysFrom')
            ->once()
            ->with('store@example.com', 'Acme Mail');

        $manager = Mockery::mock(MailManager::class);
        $manager->shouldReceive('build')
            ->once()
            ->with(Mockery::on(fn (array $config): bool => $config === [
                'name' => 'client-smtp-'.$tenant->client_id,
                'transport' => 'smtp',
                'scheme' => 'smtp',
                'host' => 'smtp.example.com',
                'port' => 587,
                'username' => 'mailer@example.com',
                'password' => 'secret',
                'timeout' => null,
                'local_domain' => null,
            ]))
            ->andReturn($mailer);

        $service = (new MailService($manager))->forTenant($tenant->codigo);

        $this->assertSame('client-smtp', $service->mailerName());
    }

    public function test_it_uses_the_default_mailer_when_client_configuration_is_not_required(): void
    {
        Mail::fake();
        config(['mail.default' => 'array']);
        $tenant = $this->createTenant();
        Integration::create([
            'integration_code' => 'email',
            'name' => 'Email',
            'requires_client_configuration' => false,
        ]);

        $service = (new MailService)->forTenant($tenant->codigo);
        $service->send('customer@example.com', 'Default mailer', '<p>Fallback</p>');

        $this->assertSame('array', $service->mailerName());
        Mail::assertSent(Mailable::class, function (Mailable $mail): bool {
            return $mail->hasTo('customer@example.com')
                && $mail->subject === 'Default mailer'
                && str_contains($mail->render(), 'Fallback');
        });
    }

    public function test_on_setup_sends_a_branded_test_email_to_the_configured_sender(): void
    {
        Mail::fake();
        $tenant = $this->createTenant();
        $this->createEmailIntegration();
        ClientIntegration::create([
            'client_id' => $tenant->client_id,
            'integration_code' => 'email',
            'integration_data' => $this->emailData(),
        ]);

        (new MailService)->forTenant($tenant->codigo)->onSetup();

        Mail::assertSent(Mailable::class, function (Mailable $mail) use ($tenant): bool {
            $html = $mail->render();

            return $mail->hasTo('store@example.com')
                && $mail->subject === 'Configuración de correo validada'
                && str_contains($html, $tenant->nombre)
                && str_contains($html, 'background-color: #112233')
                && str_contains($html, 'background-color: #445566');
        });
    }

    public function test_configuring_the_email_integration_runs_its_setup_hook(): void
    {
        Mail::fake();
        $tenant = $this->createTenant();
        $integration = $this->createEmailIntegration();

        app(ClientIntegrationService::class)->updateOrCreateIntegration(
            $tenant->client,
            $integration,
            $this->emailData(),
        );

        Mail::assertSent(Mailable::class, 1);
    }

    private function createTenant(): Tenant
    {
        $logo = Attachment::create([
            'path' => 'tenants/logo.png',
            'filename' => 'logo.png',
            'type' => AttachmentType::Image,
            'mime_type' => 'image/png',
            'extension' => 'png',
        ]);

        return Tenant::create([
            'codigo' => 'acme',
            'nombre' => 'Acme Store',
            'dominio' => 'acme.example.com',
            'primary_color' => '#778899',
            'secondary_color' => '#64748b',
            'danger_color' => '#dc2626',
            'success_color' => '#16a34a',
            'header_bg_color' => '#112233',
            'footer_bg_color' => '#445566',
            'header_logo_id' => $logo->id,
            'footer_logo_id' => $logo->id,
        ]);
    }

    private function createEmailIntegration(): Integration
    {
        return Integration::create([
            'integration_code' => 'email',
            'name' => 'Email',
        ]);
    }

    /**
     * @return array<string, string|int>
     */
    private function emailData(): array
    {
        return [
            'MAIL_SCHEME' => 'smtp',
            'MAIL_HOST' => 'smtp.example.com',
            'MAIL_PORT' => 587,
            'MAIL_USERNAME' => 'mailer@example.com',
            'MAIL_PASSWORD' => 'secret',
            'MAIL_FROM_ADDRESS' => 'store@example.com',
            'MAIL_FROM_NAME' => 'Acme Mail',
        ];
    }
}
