<?php

use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Variant;
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
{
    private const LEGACY_PRODUCT_VARIANT = 'App\\Domains\\Catalog\\Models\\ProductVariant';

    private const PREVIOUS_CATALOG_ITEM = 'App\\Domains\\CatalogNew\\Models\\CatalogItem';

    private const PREVIOUS_VARIANT = 'App\\Domains\\CatalogNew\\Models\\Variant';

    public function up(): void
    {
        Schema::table('compra_items', function (Blueprint $table): void {
            $table->unsignedBigInteger('source_catalog_item_id')->nullable()->after('compra_id');
            $table->unsignedBigInteger('source_variant_id')->nullable()->after('source_catalog_item_id');
            $table->foreignId('image_attachment_id')->nullable()->after('source_variant_id');
            $table->string('nombre')->nullable()->after('image_attachment_id');
            $table->text('descripcion')->nullable()->after('nombre');
            $table->string('slug')->nullable()->after('descripcion');
            $table->string('item_nombre')->nullable()->after('slug');
            $table->json('variant_attributes')->nullable()->after('item_nombre');
        });

        DB::table('compra_items')->orderBy('id')->each(function (object $purchaseItem): void {
            if (in_array($purchaseItem->buyable_type, [CatalogItem::class, self::PREVIOUS_CATALOG_ITEM], true)) {
                $catalogItem = DB::table('catalog_items')
                    ->where('id', $purchaseItem->buyable_id)
                    ->first();

                if ($catalogItem !== null) {
                    DB::table('compra_items')->where('id', $purchaseItem->id)->update([
                        'source_catalog_item_id' => $catalogItem->id,
                        'nombre' => $catalogItem->nombre,
                        'descripcion' => $catalogItem->descripcion,
                        'slug' => $catalogItem->slug,
                        'item_nombre' => $catalogItem->nombre,
                        'variant_attributes' => json_encode([]),
                    ]);

                    return;
                }
            }

            if (in_array($purchaseItem->buyable_type, [self::LEGACY_PRODUCT_VARIANT, Variant::class, self::PREVIOUS_VARIANT], true)) {
                $variant = DB::table('variantes')
                    ->select(['id', 'catalog_item_id'])
                    ->where('id', $purchaseItem->buyable_id)
                    ->first();

                if ($variant !== null) {
                    $catalogItem = DB::table('catalog_items')->find($variant->catalog_item_id);

                    if ($catalogItem === null) {
                        DB::table('compra_items')->where('id', $purchaseItem->id)->delete();

                        return;
                    }

                    $attributes = DB::table('variant_values as variant_value')
                        ->join('item_attributes as item_attribute', 'item_attribute.id', '=', 'variant_value.item_attribute_id')
                        ->leftJoin('attribute', 'attribute.id', '=', 'item_attribute.attribute_id')
                        ->where('variant_value.variant_id', $variant->id)
                        ->orderBy('variant_value.id')
                        ->get(['attribute.nombre as name', 'variant_value.value'])
                        ->map(fn (object $attribute): array => [
                            'name' => (string) ($attribute->name ?? ''),
                            'value' => $attribute->value,
                        ])
                        ->all();
                    $attributeDescription = collect($attributes)
                        ->map(fn (array $attribute): string => $attribute['name'] !== ''
                            ? "{$attribute['name']}: {$attribute['value']}"
                            : (string) $attribute['value'])
                        ->filter()
                        ->implode(', ');

                    DB::table('compra_items')->where('id', $purchaseItem->id)->update([
                        'source_catalog_item_id' => $catalogItem->id,
                        'source_variant_id' => $variant->id,
                        'nombre' => $catalogItem->nombre,
                        'descripcion' => $catalogItem->descripcion,
                        'slug' => $catalogItem->slug,
                        'item_nombre' => $attributeDescription === ''
                            ? $catalogItem->nombre
                            : "{$catalogItem->nombre} ({$attributeDescription})",
                        'variant_attributes' => json_encode($attributes),
                    ]);

                    return;
                }
            }

            DB::table('compra_items')->where('id', $purchaseItem->id)->delete();
        });

        Schema::table('compra_items', function (Blueprint $table): void {
            $table->dropColumn(['buyable_type', 'buyable_id']);
        });

        Schema::table('compra_items', function (Blueprint $table): void {
            $table->unsignedBigInteger('source_catalog_item_id')->nullable(false)->change();
            $table->string('nombre')->nullable(false)->change();
            $table->string('item_nombre')->nullable(false)->change();
            $table->foreign('image_attachment_id')->references('id')->on('attachments')->restrictOnDelete();
        });
    }

    public function down(): void
    {
        throw new RuntimeException('This destructive purchase migration cannot be reversed.');
    }
};
