<?php

namespace Tests\Unit\Models;

use Illuminate\Support\Facades\Date;
use App\Models\Email;
use Carbon\Carbon;
use Illuminate\Support\Facades\Config;
use Tests\TestCase;

class EmailTest extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        // Mock configuration
        Config::set('app.settings.imap_settings', json_encode([
            'host' => 'imap.gmail.com',
            'port' => 993,
            'protocol' => 'imap',
            'encryption' => 'ssl',
            'validate_cert' => true,
            'username' => 'test@gmail.com',
            'password' => 'password',
        ]));

        Config::set('app.settings.configuration_settings', json_encode([
            'fetch_messages_limit' => 15,
            'blocked_domains' => ['spam.com', 'blocked.com'],
            'date_format' => 'd M Y h:i A',
        ]));

        Config::set('app.settings.app_base_url', 'http://localhost:8000');
        Config::set('app.fetch_from_remote_db', false);
        Config::set('app.zemail_log', false);
    }

    /** @test */
    public function it_can_create_email_with_factory(): void
    {
        $email = Email::factory()->create();

        $this->assertInstanceOf(Email::class, $email);
        $this->assertIsString($email->subject);
        $this->assertIsString($email->from_email);
        $this->assertIsArray($email->to);
    }

    /** @test */
    public function it_has_correct_fillable_attributes(): void
    {
        $emailData = [
            'message_id' => '12345',
            'subject' => 'Test Subject',
            'from_name' => 'Test Sender',
            'from_email' => 'sender@example.com',
            'to' => ['recipient@example.com'],
            'body_text' => 'Plain text content',
            'body_html' => '<p>HTML content</p>',
            'is_seen' => false,
            'is_flagged' => false,
            'size' => 1024,
            'mailbox' => 'INBOX',
        ];

        $email = Email::query()->create($emailData);

        foreach ($emailData as $key => $value) {
            $this->assertEquals($value, $email->$key);
        }
    }

    /** @test */
    public function it_casts_attributes_correctly(): void
    {
        $email = Email::factory()->create([
            'to' => ['test1@example.com', 'test2@example.com'],
            'cc' => ['cc@example.com'],
            'bcc' => ['bcc@example.com'],
            'attachments' => [['file' => 'test.pdf', 'url' => 'http://example.com/test.pdf']],
            'timestamp' => '2024-01-01 12:00:00',
        ]);

        $this->assertIsArray($email->to);
        $this->assertIsArray($email->cc);
        $this->assertIsArray($email->bcc);
        $this->assertIsArray($email->attachments);
        $this->assertInstanceOf(Carbon::class, $email->timestamp);
    }

    /** @test */
    public function it_validates_email_format_in_fetch_email_from_db(): void
    {
        $result = Email::fetchEmailFromDB('invalid-email');

        $this->assertEquals([], $result);
    }

    /** @test */
    public function it_fetches_emails_from_database_with_valid_email(): void
    {
        $email1 = Email::factory()->create(['to' => ['test@example.com']]);
        $email2 = Email::factory()->create(['to' => ['other@example.com']]);
        $email3 = Email::factory()->create(['to' => ['test@example.com']]);

        $results = Email::fetchEmailFromDB('test@example.com');

        $this->assertCount(2, $results);
        $this->assertContains($email1->id, $results->pluck('id'));
        $this->assertContains($email3->id, $results->pluck('id'));
        $this->assertNotContains($email2->id, $results->pluck('id'));
    }

    /** @test */
    public function it_orders_emails_by_timestamp_descending_in_fetch_email_from_db(): void
    {
        $oldEmail = Email::factory()->create([
            'to' => ['test@example.com'],
            'timestamp' => Date::now()->subHours(2),
        ]);
        $newEmail = Email::factory()->create([
            'to' => ['test@example.com'],
            'timestamp' => Date::now(),
        ]);

        $results = Email::fetchEmailFromDB('test@example.com');

        $this->assertEquals($newEmail->id, $results->first()->id);
        $this->assertEquals($oldEmail->id, $results->last()->id);
    }

    /** @test */
    public function it_sets_correct_table_name(): void
    {
        $email = new Email;

        $this->assertEquals('emails', $email->getTable());
    }
}
