<?php

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

/**
 * channel_id held a community slug, resolved to Lemmy's numeric id on every
 * publish and every sync. It now holds that id directly; `name` remains the slug.
 *
 * Slugs cannot be converted without asking the instance for the id, and a
 * migration must not depend on a remote service: an earlier version of this file
 * did, and a rate-limited login left this and eight later migrations unapplied
 * across several releases. Channels still holding a slug are deleted instead, to
 * be recreated through the UI, which validates the community on the instance.
 */
return new class extends Migration
{
    public function up(): void
    {
        $this->deleteChannelsWithUnconvertibleIds();

        Schema::table('platform_channels', function (Blueprint $table) {
            $table->dropUnique('platform_channels_channel_id_unique');
        });

        Schema::table('platform_channels', function (Blueprint $table) {
            $table->unsignedBigInteger('remote_community_id')->nullable()->after('channel_id');
        });

        DB::table('platform_channels')->update([
            'remote_community_id' => DB::raw('CAST(channel_id AS UNSIGNED)'),
        ]);

        Schema::table('platform_channels', function (Blueprint $table) {
            $table->dropColumn('channel_id');
        });

        Schema::table('platform_channels', function (Blueprint $table) {
            $table->renameColumn('remote_community_id', 'channel_id');
        });

        Schema::table('platform_channels', function (Blueprint $table) {
            $table->unsignedBigInteger('channel_id')->nullable(false)->change();
            $table->unique(['platform_instance_id', 'channel_id'], 'platform_channels_channel_id_unique');
        });
    }

    public function down(): void
    {
        Schema::table('platform_channels', function (Blueprint $table) {
            $table->dropUnique('platform_channels_channel_id_unique');
        });

        Schema::table('platform_channels', function (Blueprint $table) {
            $table->string('channel_id')->change();
        });

        DB::table('platform_channels')->update(['channel_id' => DB::raw('name')]);

        Schema::table('platform_channels', function (Blueprint $table) {
            $table->unique(['platform_instance_id', 'channel_id'], 'platform_channels_channel_id_unique');
        });
    }

    /**
     * Routes, keywords, route articles and channel posts cascade from the
     * database. article_publications does not have its foreign key until
     * 000023, which deletes whatever this leaves orphaned.
     */
    private function deleteChannelsWithUnconvertibleIds(): void
    {
        $doomed = DB::table('platform_channels')
            ->get(['id', 'name', 'channel_id'])
            ->reject(fn (object $channel) => ctype_digit((string) $channel->channel_id))
            ->pluck('name', 'id');

        if ($doomed->isEmpty()) {
            return;
        }

        Log::warning(sprintf(
            'Deleting %d channel(s) whose community id is a slug rather than a numeric id: %s. Recreate them from the Channels page.',
            $doomed->count(),
            $doomed->implode(', '),
        ));

        DB::table('platform_channels')->whereIn('id', $doomed->keys())->delete();
    }
};
