<?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->backfillLegacyNewsIds();
        }

        if (! Schema::hasTable('news_article_comments')) {
            Schema::create('news_article_comments', function (Blueprint $table): void {
                $table->id();
                $table->unsignedInteger('legacy_id')->nullable()->unique();
                $table->unsignedInteger('legacy_user_id')->nullable()->index();
                $table->foreignId('article_id')->constrained('news_articles')->cascadeOnDelete();
                $table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
                $table->foreignId('parent_id')->nullable()->constrained('news_article_comments')->nullOnDelete();
                $table->string('author_name', 120)->nullable();
                $table->text('body');
                $table->text('rendered_body')->nullable();
                $table->string('status', 24)->default('visible');
                $table->timestamp('legacy_posted_at')->nullable();
                $table->timestamps();
                $table->softDeletes();

                $table->index(['article_id', 'status', 'created_at'], 'news_article_comments_article_status_created_idx');
            });
        }
    }

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

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

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

        if ($columns === []) {
            return;
        }

        Schema::table('news_articles', function (Blueprint $table) use ($columns): void {
            foreach ($columns as $column) {
                if ($column === 'legacy_news_id') {
                    $table->dropUnique(['legacy_news_id']);
                }
            }

            $table->dropColumn($columns);
        });
    }

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

        foreach (['comments_enabled', 'legacy_news_id'] 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', 'comments_enabled')) {
                $table->boolean('comments_enabled')->default(false)->after('forum_thread_id')->index();
            }

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

    private function backfillLegacyNewsIds(): void
    {
        if (! Schema::hasColumn('news_articles', 'legacy_news_id')) {
            return;
        }

        DB::table('news_articles')
            ->select(['id', 'canonical_url', 'legacy_news_id'])
            ->whereNull('legacy_news_id')
            ->whereNotNull('canonical_url')
            ->orderBy('id')
            ->chunkById(200, function ($rows): void {
                foreach ($rows as $row) {
                    $canonicalUrl = trim((string) ($row->canonical_url ?? ''));

                    if ($canonicalUrl === '' || preg_match('#/legacy/news/(\d+)$#', $canonicalUrl, $matches) !== 1) {
                        continue;
                    }

                    $legacyNewsId = (int) ($matches[1] ?? 0);
                    if ($legacyNewsId < 1) {
                        continue;
                    }

                    DB::table('news_articles')
                        ->where('id', $row->id)
                        ->update(['legacy_news_id' => $legacyNewsId]);
                }
            });
    }
};