<?php

namespace App\Console\Commands;

use App\Facades\Settings;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Mtc\ContentManager\Facades\Media;
use Mtc\MercuryDataModels\MediaUse;
use Mtc\MercuryDataModels\Vehicle;

class RemoveArchivedVehicles extends Command
{
    private static array $purge_providers = [
        'auto-trader',
        'skupenet',
    ];

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'vehicles:purge-soft-deletes';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Remove old/archived vehicles';

    private int $defaultExpiryDays = 90;
    private int $defaultFullyPurgeDays = 1095; // 3 years

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $expiry = Settings::get('app-old-stock-expiry-days') ?: $this->defaultExpiryDays;
        $fullExpiry = Settings::get('app-old-stock-full-purge-days') ?: $this->defaultFullyPurgeDays;
        if (empty(tenant('live_at'))) {
            // Sites not live should be cleared out a lot quicker to avoid bloating of storage
            $expiry = 3;
            $fullExpiry = 7;
        }
        $this->output->info('Removing vehicles that have been removed for X days: ' . $expiry);
        Vehicle::onlyTrashed()
            ->whereNull('purged_at')
            ->where('deleted_at', '<=', Carbon::now()->subDays($expiry))
            ->chunk(250, fn($collection) => $collection
                ->tap(fn($collection) => $this->output->info('Records to remove in batch: ' . $collection->count()))
                ->each(fn(Vehicle $vehicle) => $this->purgeNonEssentialData($vehicle)));

        $this->output->info('Processing vehicles for full purge after days: ' . $fullExpiry);
        Vehicle::onlyTrashed()
            ->where('deleted_at', '<=', Carbon::now()->subDays($fullExpiry))
            ->chunk(250, function ($collection) {
                $this->output->info('Fully deleting batch size: ' . $collection->count());
                $collection->each(fn(Vehicle $vehicle) => $this->fullPurge($vehicle));
            });

        $this->output->info('Removing non-primary for archived vehicles with images from stock provider');
        Vehicle::onlyTrashed()
            ->where('deleted_at', '<=', Carbon::now()->subDays(3))
            ->chunk(250, function ($collection) {
                $collection->map(fn(Vehicle $vehicle) => $vehicle->mediaUses()
                    ->with('media')
                    ->whereHas('media', fn($query) => $query->whereIn('image_provider', self::$purge_providers))
                    ->get())
                    ->each(fn($collection) => $this->removeMediaUses($collection));
            });

        $clear_counter = 100;
        $this->output->info('Removing media uses for records that do not exist (even trashed)');
        MediaUse::query()
            ->whereDoesntHaveMorph('owner', [Vehicle::class], fn ($query) => $query->withTrashed())
            ->chunk(500, function (Collection $collection) use (&$clear_counter) {
                if (--$clear_counter <= 0) {
                    return false; // tells chunk to break
                }
                $this->removeMediaUses($collection);
            });
    }

    private function purgeNonEssentialData(Vehicle $vehicle): void
    {
        $vehicle->specs()->delete();
        $vehicle->features()->delete();
        $vehicle->financeExamples()->delete();
        $vehicle->autoTraderData()->delete();
        $vehicle->priceHistory()->delete();
        $vehicle->conversions()->delete();
        $vehicle->views()->delete();
        $vehicle->attributeValues()->delete();
        $vehicle->labels()->sync([]);
        $vehicle->equipment()->delete();
        $vehicle->stockSyncLogs()->delete();

        $this->removeMediaUses($vehicle->mediaUses()->with('media.uses')->where('primary', '!=', 1)->get());

        $vehicle->purged_at = now();
        $vehicle->save();
    }

    private function fullPurge(Vehicle $vehicle): void
    {
        $this->removeMediaUses($vehicle->mediaUses()->get());
        $vehicle->forceDelete();
    }

    private function removeMediaUses(Collection $uses): void
    {
        // with other uses, can't remove file, only use itself
        $uses->filter(fn($use) => is_null($use->media) || $use->media->uses->count() > 1)
            ->each(fn($use) => $use->delete());

        $without_other_uses = $uses
            ->filter(fn($use) => $use->media?->uses->count() <= 1)
            ->pluck('media_id')
            ->toArray();
        if (!empty($without_other_uses)) {
            Media::destroyMedia($without_other_uses);
        }
    }
}
