<?php

namespace App\Jobs;

use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Str;
use Mtc\ContentManager\Models\MediaFolder;
use Mtc\ContentManager\Models\MediaUse;
use Mtc\MercuryDataModels\CarConfiguratorModel;
use Mtc\MercuryDataModels\Media;

class ImportConfiguratorImages implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    /**
     * Create a new job instance.
     */
    public function __construct(private readonly CarConfiguratorModel $configurator, private readonly array $data)
    {
        $this->onQueue('bulk-media');
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        $folder = $this->getImageFolder();
        foreach (['interior', 'exterior'] as $type) {
            $unique_by_flag = collect();
            collect($this->data[$type] ?? [])
                ->map(function ($row) use ($folder, $type) {
                    $this->ensureSelections($row);
                    $images = collect(array_unique($row['images'] ?? []))
                        ->map(fn ($image) => strtok($image, '?'))
                        ->unique();

                    $flags = collect($row)
                        ->filter()
                        ->forget('engine') // engine does not change images
                        ->forget('images')
                        ->map(fn ($item) => Str::slug(trim($item)))
                        ->prepend($type)
                        ->implode('-');
                    $meta = $images->keyBy(fn ($image) => $image)
                        ->map(fn ($image) => [
                            'folder_id' => $folder,
                        ]);

                    return [
                        'images' => $images,
                        'flags' => $flags,
                        'meta' => $meta
                    ];
                })
                ->filter(function ($image_data) use ($unique_by_flag) {
                    if ($unique_by_flag->contains($image_data['flags'])) {
                        return false;
                    }
                    $unique_by_flag->prepend($image_data['flags']);
                    return true;
                })
                ->each(fn (array $image_data) => $this->importAsExternalImages($image_data, $folder));
        }
    }

    private function getImageFolder(): int
    {
        $folder = MediaFolder::query()
            ->where('name', $this->configurator->name)
            ->whereHas('parent', fn ($parent) => $parent->where('name', 'Car Configurator'))
            ->first();
        if ($folder) {
            return $folder->id;
        }

        $parent = MediaFolder::query()
            ->firstOrCreate([
                'name' => 'Car Configurator',
                'parent_id' => null,
            ]);
        $folder = $parent->children()
            ->create([
                'name' => $this->configurator->name,
            ]);
        return $folder->id;
    }

    private function ensureSelections($row): void
    {
        collect($row)
            ->filter()
            ->forget('images')
            ->each(function ($name, $relationName) {
                $relation = Str::plural($relationName);
                if (in_array($relation, CarConfiguratorModel::$relationship_models)) {
                    $this->configurator->$relation()
                        ->firstOrCreate([
                            'name' => trim($name)
                        ]);
                } else {
                    $section_id = $this->configurator->sections()->where('name', $relation)->first()?->id;
                    $this->configurator->custom()
                        ->firstOrCreate([
                            'section_id' => $section_id,
                            'name' => trim($name),
                        ]);
                }
            });
    }

    private function importAsExternalImages(array $image_data, int $folder): void
    {
        $date = Carbon::now()->format('Y-m');
        foreach ($image_data['images'] as $image) {
            $media = Media::query()
                ->firstOrCreate([
                    'image_provider' => 'Configurator',
                    'source_filename' => $image
                ], [
                    'type' => 'image',
                    'external' => true,
                    'src' => $image,
                    'path' => '',
                    'upload_date' => $date,
                    'folder_id' => $folder,
                ]);

            $use = MediaUse::query()
                ->firstOrCreate([
                    'media_id' => $media->id,
                    'owner_type' => $this->configurator->getMorphClass(),
                    'owner_id' => $this->configurator->id,
                ], [
                    'flags' => [$image_data['flags'] => true],
                ]);
            if (!$use->wasRecentlyCreated) {
                $flags = array_merge($use->flags ?? [], [$image_data['flags'] => true]);
                $use->update(['flags' => $flags]);
            }
        }
    }
}
