<?php

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
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        if (! Schema::hasTable('settings')) {
            $this->createSpatieSettingsTable();

            $this->seedDefaultSettings();

            return;
        }

        if (Schema::hasColumn('settings', 'group')) {
            // Already migrated.
            return;
        }

        Schema::rename('settings', 'legacy_settings');

        $this->createSpatieSettingsTable();

        $legacySettings = DB::table('legacy_settings')->pluck('value', 'key')->toArray();

        $records = $this->buildSettingsRecords($legacySettings);

        if (! empty($records)) {
            DB::table('settings')->insert($records);
        }

        Schema::dropIfExists('legacy_settings');
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        if (! Schema::hasTable('settings')) {
            return;
        }

        if (Schema::hasColumn('settings', 'key')) {
            // Already reverted.
            return;
        }

        Schema::rename('settings', 'spatie_settings');

        Schema::create('settings', function (Blueprint $table): void {
            $table->id();
            $table->string('key')->unique();
            $table->text('value')->nullable();
            $table->timestamps();
        });

        $spatieSettings = DB::table('spatie_settings')
            ->where('group', 'general')
            ->get(['name', 'payload']);

        $now = now();

        $rows = $spatieSettings
            ->map(function ($setting) use ($now) {
                $value = json_decode($setting->payload, true);

                if (is_bool($value)) {
                    $value = $value ? '1' : '0';
                }

                return [
                    'key' => $setting->name,
                    'value' => is_array($value) ? json_encode($value) : (string) $value,
                    'created_at' => $now,
                    'updated_at' => $now,
                ];
            })
            ->toArray();

        if (! empty($rows)) {
            DB::table('settings')->insert($rows);
        }

        Schema::dropIfExists('spatie_settings');
    }

    protected function createSpatieSettingsTable(): void
    {
        Schema::create('settings', function (Blueprint $table): void {
            $table->id();
            $table->string('group');
            $table->string('name');
            $table->boolean('locked')->default(false);
            $table->json('payload');
            $table->timestamps();
            $table->unique(['group', 'name']);
        });
    }

    protected function buildSettingsRecords(array $legacySettings): array
    {
        $defaults = [
            'gallery_heading' => 'Style Gallery',
            'require_gallery_password' => false,
            'gallery_password_hash' => null,
            'gallery_expires_at' => null,
            'gallery_access_duration_minutes' => null,
            'new_image_timespan_minutes' => 60,
            'image_refresh_interval' => 30_000,
            'max_number_of_copies' => 3,
            'show_print_button' => true,
            'selected_printer' => null,
            'custom_printer_address' => null,
            'default_style_id' => null,
        ];

        $intKeys = [
            'new_image_timespan_minutes',
            'image_refresh_interval',
            'max_number_of_copies',
            'default_style_id',
            'gallery_access_duration_minutes',
        ];

        $boolKeys = ['show_print_button', 'require_gallery_password'];

        $now = now();

        return collect($defaults)
            ->map(function ($default, string $key) use ($legacySettings) {
                return array_key_exists($key, $legacySettings)
                    ? $legacySettings[$key]
                    : $default;
            })
            ->map(function ($value, string $key) use ($intKeys, $boolKeys) {
                if (in_array($key, $intKeys, true)) {
                    return is_null($value) || $value === '' ? null : (int) $value;
                }

                if (in_array($key, $boolKeys, true)) {
                    if (is_null($value) || $value === '') {
                        return false;
                    }

                    if (is_bool($value)) {
                        return $value;
                    }

                    return in_array((string) $value, ['1', 'true', 'on'], true);
                }

                return $value;
            })
            ->map(function ($value, string $key) use ($now) {
                return [
                    'group' => 'general',
                    'name' => $key,
                    'payload' => json_encode($value),
                    'locked' => false,
                    'created_at' => $now,
                    'updated_at' => $now,
                ];
            })
            ->values()
            ->toArray();
    }

    protected function seedDefaultSettings(): void
    {
        $records = $this->buildSettingsRecords([]);

        if (! empty($records)) {
            DB::table('settings')->insert($records);
        }
    }
};
