<?php

namespace App\Modules\Stock;

use App\Contracts\SalesChannel;
use App\Contracts\StockProvider;
use App\Events\StockSyncFinished;
use App\Facades\Settings;
use App\Imports\AutoTraderApiToVehicleImport;
use App\Jobs\AutoTraderCSVExportJob;
use App\Services\AutoTraderApi;
use App\Services\AutoTraderHub;
use Carbon\Carbon;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Mtc\AutoTraderStock\Services\AutoTraderService;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\SalesChannelHistory;
use Mtc\MercuryDataModels\Vehicle;

class AutoTraderStock implements StockProvider, SalesChannel
{
    use DispatchesJobs;

    private Collection $dealerships;
    private bool $fullSync;

    public function __construct(
        private readonly AutoTraderApiToVehicleImport $import,
        private readonly AutoTraderHub $export
    ) {
    }


    public function enabled(): bool
    {
        return (Settings::get('stock-auto-trader-enabled', false) ?? false)
            || (Settings::get('sales-channels-auto-trader-enabled', false) ?? false);
    }

    public function name(): string
    {
        return 'AutoTrader';
    }

    /**
     * Fields to add to dealership management
     *
     * @return array[]
     */
    public function dealershipAdditionalDataFields()
    {
        return [
            'auto-trader-location-id' => [
                'type' => 'text',
                'label' => 'Dealer ID within AutoTrader',
            ],
        ];
    }

    public function runScheduledImport(bool $fullSync = true): void
    {
        $this->fullSync = $fullSync;
        Vehicle::query()
            ->where('stock_provider', $this->import->getProviderName())
            ->update(['was_recently_synced' => 0]);

        $this->dealerships = $this->loadDealerships();
        $this->dealerships
            ->each(fn ($dealership, $dealership_id) => $this->syncDealershipData($dealership, $dealership_id));

        if (Settings::get('auto-trader-stock-remove-old-vehicles') && $this->fullSync) {
            Vehicle::query()
                ->where('stock_provider', $this->import->getProviderName())
                ->where('was_recently_synced', 0)
                ->delete();
        }
        Event::dispatch(new StockSyncFinished('auto-trader'));
    }

    private function syncDealershipData($dealership, $dealership_id)
    {
        $config = config('auto_trader_stock', []);
        $config['is_production'] = config('auto_trader_stock.use_sandbox') === false;

        $service = new AutoTraderService($dealership, App::make(AutoTraderApi::class));
        $vehicles = $service->fetchVehicles();
        $this->import->setDealershipId($dealership_id);

        $vehicles->filter(fn($vehicle_data) => $this->fullSync || $this->isRecentlyUpdated($vehicle_data))
            ->each(fn($vehicle_data) => $this->syncVehicle($vehicle_data, $service));
    }

    public function loadDealerships()
    {
        $this->dealerships = Dealership::all()
            ->each(function (Dealership $dealership) {
                $dealership->stock_location = $dealership->data['auto-trader-location-id'] ?? null;
            });

        return $this->dealerships
            ->keyBy(fn(Dealership $dealership) => $dealership->id)
            ->map(fn(Dealership $dealership) => $dealership->data['auto-trader-location-id'] ?? null)
            ->filter();
    }

    public function runScheduledExport(): void
    {

        if (Settings::get('sales-channels-auto-trader-method') === 'ftp') {
            $this->dispatch(new AutoTraderCSVExportJob());
        } else {
            $this->exportViaApi();
        }
    }

    private function syncVehicle(array $vehicle_data, AutoTraderService $service): void
    {
        if (!empty($vehicle_data['vehicle']['derivativeId']) && !$this->import->isVehicleDeleted($vehicle_data)) {
            $vehicle_data['enriched_data'] = $service->fetchAdditional($vehicle_data);
        }
        if ($this->import->exists($vehicle_data) === false) {
            $this->import->add($vehicle_data);
        } else {
            $this->import->update($vehicle_data);
        }
    }

    private function exportViaApi(): void
    {
        try {
            $this->export->setToken(Settings::get('auto-trader-hub-token'));
            $reference = $this->export->initExport();

            $query = Vehicle::query()
                ->with([
                    'dealership',
                    'make',
                    'model',
                    'fuelType',
                    'drivetrain',
                    'transmission',
                    'bodyStyle',
                    'mediaUses.media',
                    'features',
                    'specs',
                ])
                ->exportable();

            $query->chunk(100, fn(Collection $batch) => $this->export->bulkExport($reference, $batch));
            $this->export->triggerExport($reference);

            SalesChannelHistory::store('auto-trader-sales', true, $query->count() . ' records exported');
        } catch (\Exception $exception) {
            SalesChannelHistory::store('auto-trader-sales', false, $exception->getMessage());
            Log::error('AutoTrader stock export failed with error:' . $exception->getMessage(), [
                'tenant' => tenant('id'),
            ]);
        }
    }

    private function isRecentlyUpdated(array $vehicle_data): bool
    {
        try {
            return Carbon::parse($vehicle_data['metadata']['lastUpdatedByAdvertiser'])
                ->greaterThanOrEqualTo(Carbon::now()->subHours(24));
        } catch (\Exception $exception) {
            // issue parsing updated timestamp
        }
        return true;
    }

    public function setAdvertFields(bool $isPublished): array
    {
        return [
            'autotraderAdvert' => $isPublished ? 'PUBLISHED' : 'NOT_PUBLISHED',
            'profileAdvert' => $isPublished ? 'PUBLISHED' : 'NOT_PUBLISHED',
        ];
    }
}
