<?php

namespace App\Modules\ImageSync;

use App\Facades\Settings;
use App\Jobs\ImportImagesFromUrlList;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Http;
use Mtc\ContentManager\Models\MediaUse;
use Mtc\MercuryDataModels\Vehicle;

class Phyron implements ImageSync
{
    use DispatchesJobs;

    public function sync(): void
    {
        collect(Http::get(Settings::get('image-sync-phryon-manifest-file'))->json('products'))
            ->each(fn ($entry, $key) => $this->processEntry($entry, $key));
    }

    private function processEntry(array $entry, $key): void
    {
        $this->findVehicles($entry, $key)
            ->each(function (Vehicle $vehicle) use ($entry) {
                if (Settings::get('image-sync-phryon-process-video')) {
                    $this->processVideo($entry, $vehicle);
                }

                if (Settings::get('image-sync-phryon-process-images')) {
                    $this->processImages($entry, $vehicle);
                }
            });
    }

    /**
     * @param string $vrm
     * @return Collection
     */
    private function findVehicles(array $entry, $uuid): Collection
    {
        return Vehicle::query()
            ->when(
                !empty($entry['vrm']),
                fn ($query) => $query->where('vrm_condensed', $entry['vrm']),
                fn ($query) => $query->when(
                    !empty($entry['vin']),
                    fn ($subQuery) => $subQuery->where('vrm_condensed', $entry['vin']),
                    fn ($subQuery) => $subQuery->where('uuid', $uuid)
                )
            )
            ->get();
    }

    private function processVideo(array $entry, Vehicle $vehicle): void
    {
        $video = collect($entry['files'])
            ->filter(fn ($file) => $file['type'] == 'video')
            ->first();

        if ($video) {
            $vehicle->update([
                'main_video_url' => $video['embed_url'],
            ]);
        }
    }

    private function processImages(array $entry, Model|Vehicle $vehicle)
    {
        $images = collect($entry['files'])->filter(fn ($file) => $file['type'] == 'image');
        if ($images->count() == 0) {
            return;
        }

        $image_urls = $images->pluck('url');
        $remove_others = $images->count() && Settings::get('image-sync-phryon-remove-other-images');
        $remove_replaced = $images->count() && Settings::get('image-sync-phryon-remove-replaced-images');

        $this->dispatch(new ImportImagesFromUrlList(
            $image_urls,
            $vehicle,
            false,
            'phyron',
            true,
            true,
            $this->shouldUpdatePrimary($remove_others, $images, $vehicle)
        ));

        if ($remove_others) {
            $this->removeNonPhyronImages($vehicle);
        }

        if ($remove_replaced) {
            $this->removePhyronReplacedImages($vehicle, $images);
        }
    }

    /**
     * Phyron can send through partial set - e.g. image with sort order 2.
     * In this case we do not want to mark the first image in the list (sort order 2) as primary
     *
     * @param bool $remove_others
     * @param Collection $images
     * @param Model|Vehicle $vehicle
     * @return bool
     */
    private function shouldUpdatePrimary(bool $remove_others, Collection $images, Model|Vehicle $vehicle): bool
    {
        return $remove_others
            && $images->filter(fn ($image) => ($image['sort_order'] ?? 0) == 1)->isNotEmpty();
    }

    private function removeNonPhyronImages(Model|Vehicle $vehicle): void
    {
        $vehicle->mediaUses()
            ->whereHas('media', fn ($query) => $query->where('image_provider', '!=', 'phyron'))
            ->delete();
    }

    private function removePhyronReplacedImages(Model|Vehicle $vehicle, Collection $images)
    {
        $to_remove = $images->pluck('original_image');
        $vehicle->mediaUses
            ->filter(fn (MediaUse $mediaUse) => $to_remove->search($mediaUse->getUrl('large')) !== false)
            ->each(fn (MediaUse $mediaUse) => $mediaUse->delete());
    }
}
