<?php

declare(strict_types=1);

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        if (Schema::hasTable('news_articles')) {
            $this->addNewsArticleColumns();
            $this->backfillNewsArticleColumns();
        }

        if (! Schema::hasTable('news_article_relations')) {
            Schema::create('news_article_relations', function (Blueprint $table): void {
                $table->id();
                $table->unsignedBigInteger('article_id')->index();
                $table->string('entity_type', 40)->index();
                $table->unsignedBigInteger('entity_id')->index();
                $table->string('context_label', 120)->nullable();
                $table->unsignedSmallInteger('sort_order')->default(0);
                $table->timestamps();

                $table->foreign('article_id')->references('id')->on('news_articles')->onDelete('cascade');
                $table->unique(['article_id', 'entity_type', 'entity_id'], 'news_article_relations_unique');
            });
        }
    }

    public function down(): void
    {
        Schema::dropIfExists('news_article_relations');

        if (! Schema::hasTable('news_articles')) {
            return;
        }

        $columns = [
            'editorial_status',
            'type',
            'is_pinned',
            'canonical_url',
        ];

        $existing = array_values(array_filter($columns, static fn (string $column): bool => Schema::hasColumn('news_articles', $column)));

        if ($existing !== []) {
            Schema::table('news_articles', function (Blueprint $table) use ($existing): void {
                $table->dropColumn($existing);
            });
        }
    }

    private function addNewsArticleColumns(): void
    {
        $needsTableChange = false;

        foreach (['editorial_status', 'type', 'is_pinned', 'canonical_url'] as $column) {
            if (! Schema::hasColumn('news_articles', $column)) {
                $needsTableChange = true;
                break;
            }
        }

        if (! $needsTableChange) {
            return;
        }

        Schema::table('news_articles', function (Blueprint $table): void {
            if (! Schema::hasColumn('news_articles', 'editorial_status')) {
                $table->string('editorial_status', 30)->default('draft')->after('status')->index();
            }

            if (! Schema::hasColumn('news_articles', 'type')) {
                $table->string('type', 40)->default('announcement')->after('cover_image')->index();
            }

            if (! Schema::hasColumn('news_articles', 'is_pinned')) {
                $table->boolean('is_pinned')->default(false)->after('is_featured')->index();
            }

            if (! Schema::hasColumn('news_articles', 'canonical_url')) {
                $table->string('canonical_url')->nullable()->after('meta_description');
            }
        });
    }

    private function backfillNewsArticleColumns(): void
    {
        DB::table('news_articles')
            ->select(['id', 'status', 'editorial_status', 'type'])
            ->orderBy('id')
            ->chunkById(200, function ($rows): void {
                foreach ($rows as $row) {
                    $payload = [];

                    if (property_exists($row, 'editorial_status') && ($row->editorial_status === null || $row->editorial_status === '')) {
                        $payload['editorial_status'] = match ((string) $row->status) {
                            'published' => 'published',
                            'scheduled' => 'scheduled',
                            default => 'draft',
                        };
                    }

                    if (property_exists($row, 'type') && ($row->type === null || $row->type === '')) {
                        $payload['type'] = 'announcement';
                    }

                    if ($payload !== []) {
                        DB::table('news_articles')->where('id', $row->id)->update($payload);
                    }
                }
            });
    }
};