<?php

namespace Tests\Unit\Models;

use App\Models\Article;
use App\Models\ArticlePublication;
use App\Models\PlatformChannel;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ArticlePublicationTest extends TestCase
{
    use RefreshDatabase;

    public function test_fillable_fields(): void
    {
        $fillableFields = ['article_id', 'platform_channel_id', 'post_id', 'published_at', 'published_by', 'platform', 'publication_data'];
        $publication = new ArticlePublication;

        $this->assertEquals($fillableFields, $publication->getFillable());
    }

    public function test_table_name(): void
    {
        $publication = new ArticlePublication;

        $this->assertEquals('article_publications', $publication->getTable());
    }

    public function test_casts_published_at_to_datetime(): void
    {
        $timestamp = now()->subHours(2);
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['published_at' => $timestamp]);

        $this->assertInstanceOf(Carbon::class, $publication->published_at);
        $this->assertEquals($timestamp->format('Y-m-d H:i:s'), $publication->published_at->format('Y-m-d H:i:s'));
    }

    public function test_casts_publication_data_to_array(): void
    {
        $publicationData = [
            'post_url' => 'https://lemmy.world/post/123',
            'platform_response' => [
                'id' => 123,
                'status' => 'success',
                'metadata' => ['views' => 0, 'votes' => 0],
            ],
            'retry_count' => 0,
        ];

        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['publication_data' => $publicationData]);

        $this->assertIsArray($publication->publication_data);
        $this->assertEquals($publicationData, $publication->publication_data);
    }

    public function test_belongs_to_article_relationship(): void
    {
        $article = Article::factory()->create();
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['article_id' => $article->id]);

        $this->assertInstanceOf(Article::class, $publication->article);
        $this->assertEquals($article->id, $publication->article->id);
        $this->assertEquals($article->title, $publication->article->title);
    }

    public function test_publication_creation_with_factory(): void
    {
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create();

        $this->assertInstanceOf(ArticlePublication::class, $publication);
        $this->assertNotNull($publication->article_id);
        $this->assertNotNull($publication->platform_channel_id);
        $this->assertIsString($publication->post_id);
        $this->assertInstanceOf(Carbon::class, $publication->published_at);
        $this->assertIsString($publication->published_by);
    }

    public function test_publication_creation_with_explicit_values(): void
    {
        $article = Article::factory()->create();
        $channel = PlatformChannel::factory()->create();
        $publicationData = ['status' => 'success', 'external_id' => '12345'];
        $publishedAt = now()->subHours(1);

        $publication = ArticlePublication::create([
            'article_id' => $article->id,
            'platform_channel_id' => $channel->id,
            'post_id' => 'post-123',
            'published_at' => $publishedAt,
            'published_by' => 'test_bot',
            'platform' => 'lemmy',
            'publication_data' => $publicationData,
        ]);

        $this->assertEquals($article->id, $publication->article_id);
        $this->assertEquals($channel->id, $publication->platform_channel_id);
        $this->assertEquals('post-123', $publication->post_id);
        $this->assertEquals($publishedAt->format('Y-m-d H:i:s'), $publication->published_at->format('Y-m-d H:i:s'));
        $this->assertEquals('test_bot', $publication->published_by);
        $this->assertEquals('lemmy', $publication->platform);
        $this->assertEquals($publicationData, $publication->publication_data);
    }

    public function test_publication_factory_recently_published_state(): void
    {
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->recentlyPublished()->create();

        $this->assertInstanceOf(Carbon::class, $publication->published_at);
        $this->assertTrue($publication->published_at->isAfter(now()->subDay()));
        $this->assertTrue($publication->published_at->isBefore(now()->addMinute()));
    }

    public function test_publication_update(): void
    {
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create([
            'post_id' => 'original-id',
            'published_by' => 'original_user',
        ]);

        $publication->update([
            'post_id' => 'updated-id',
            'published_by' => 'updated_user',
        ]);

        $publication->refresh();

        $this->assertEquals('updated-id', $publication->post_id);
        $this->assertEquals('updated_user', $publication->published_by);
    }

    public function test_publication_deletion(): void
    {
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create();
        $publicationId = $publication->id;

        $publication->delete();

        $this->assertDatabaseMissing('article_publications', ['id' => $publicationId]);
    }

    public function test_publication_data_can_be_empty_array(): void
    {
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['publication_data' => []]);

        $this->assertIsArray($publication->publication_data);
        $this->assertEmpty($publication->publication_data);
    }

    public function test_publication_data_can_be_null(): void
    {
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['publication_data' => null]);

        $this->assertNull($publication->publication_data);
    }

    public function test_publication_data_can_be_complex_structure(): void
    {
        $complexData = [
            'platform_response' => [
                'post_id' => 'abc123',
                'url' => 'https://lemmy.world/post/abc123',
                'created_at' => '2023-01-01T12:00:00Z',
                'author' => [
                    'id' => 456,
                    'name' => 'bot_user',
                    'display_name' => 'Bot User',
                ],
            ],
            'metadata' => [
                'retry_attempts' => 1,
                'processing_time_ms' => 1250,
                'error_log' => [],
            ],
            'analytics' => [
                'initial_views' => 0,
                'initial_votes' => 0,
                'engagement_tracked' => false,
            ],
        ];

        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['publication_data' => $complexData]);

        $this->assertEquals($complexData, $publication->publication_data);
        $this->assertEquals('abc123', $publication->publication_data['platform_response']['post_id']);
        $this->assertEquals(1, $publication->publication_data['metadata']['retry_attempts']);
        $this->assertFalse($publication->publication_data['analytics']['engagement_tracked']);
    }

    public function test_publication_with_specific_published_at(): void
    {
        $timestamp = now()->subHours(3);
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['published_at' => $timestamp]);

        $this->assertInstanceOf(Carbon::class, $publication->published_at);
        $this->assertEquals($timestamp->format('Y-m-d H:i:s'), $publication->published_at->format('Y-m-d H:i:s'));
    }

    public function test_publication_with_specific_published_by(): void
    {
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['published_by' => 'custom_bot']);

        $this->assertEquals('custom_bot', $publication->published_by);
    }

    public function test_publication_with_specific_platform(): void
    {
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['platform' => 'lemmy']);

        $this->assertEquals('lemmy', $publication->platform);
    }

    public function test_publication_timestamps(): void
    {
        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create();

        $this->assertNotNull($publication->created_at);
        $this->assertNotNull($publication->updated_at);
        $this->assertInstanceOf(Carbon::class, $publication->created_at);
        $this->assertInstanceOf(Carbon::class, $publication->updated_at);
    }

    public function test_multiple_publications_for_same_article(): void
    {
        $article = Article::factory()->create();
        $channel1 = PlatformChannel::factory()->create();
        $channel2 = PlatformChannel::factory()->create();

        /** @var ArticlePublication $publication1 */
        $publication1 = ArticlePublication::factory()->create([
            'article_id' => $article->id,
            'platform_channel_id' => $channel1->id,
            'post_id' => 'post-1',
        ]);

        /** @var ArticlePublication $publication2 */
        $publication2 = ArticlePublication::factory()->create([
            'article_id' => $article->id,
            'platform_channel_id' => $channel2->id,
            'post_id' => 'post-2',
        ]);

        $this->assertEquals($article->id, $publication1->article_id);
        $this->assertEquals($article->id, $publication2->article_id);
        $this->assertNotEquals($publication1->platform_channel_id, $publication2->platform_channel_id);
        $this->assertNotEquals($publication1->post_id, $publication2->post_id);
    }

    public function test_publication_with_different_platforms(): void
    {
        /** @var ArticlePublication $publication1 */
        $publication1 = ArticlePublication::factory()->create(['platform' => 'lemmy']);
        /** @var ArticlePublication $publication2 */
        $publication2 = ArticlePublication::factory()->create(['platform' => 'lemmy']);

        $this->assertEquals('lemmy', $publication1->platform);
        $this->assertEquals('lemmy', $publication2->platform);
    }

    public function test_publication_post_id_variations(): void
    {
        /** @var ArticlePublication[] $publications */
        $publications = [
            ArticlePublication::factory()->create(['post_id' => 'numeric-123']),
            ArticlePublication::factory()->create(['post_id' => 'uuid-'.fake()->uuid()]),
            ArticlePublication::factory()->create(['post_id' => 'alphanumeric_post_456']),
            ArticlePublication::factory()->create(['post_id' => '12345']),
        ];

        foreach ($publications as $publication) {
            $this->assertIsString($publication->post_id);
            $this->assertNotEmpty($publication->post_id);
        }
    }

    public function test_publication_data_with_error_information(): void
    {
        $errorData = [
            'status' => 'failed',
            'error' => [
                'code' => 403,
                'message' => 'Insufficient permissions',
                'details' => 'Bot account lacks posting privileges',
            ],
            'retry_info' => [
                'max_retries' => 3,
                'current_attempt' => 2,
                'next_retry_at' => '2023-01-01T13:00:00Z',
            ],
        ];

        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['publication_data' => $errorData]);

        $this->assertEquals('failed', $publication->publication_data['status']);
        $this->assertEquals(403, $publication->publication_data['error']['code']);
        $this->assertEquals(2, $publication->publication_data['retry_info']['current_attempt']);
    }

    public function test_publication_relationship_with_article_data(): void
    {
        $article = Article::factory()->create([
            'title' => 'Test Article Title',
            'description' => 'Test article description',
        ]);

        /** @var ArticlePublication $publication */
        $publication = ArticlePublication::factory()->create(['article_id' => $article->id]);

        $this->assertEquals('Test Article Title', $publication->article->title);
        $this->assertEquals('Test article description', $publication->article->description);
    }
}
