<?php

namespace App\Modules\Stock;

use App\Contracts\StockProvider;
use App\Events\StockSyncFinished;
use App\Facades\Settings;
use App\Imports\VehicleImport;
use App\Models\ImportMap as ImportMapModel;
use App\Modules\Stock\ImportMapSources\ImportMapSourceFactory;
use App\Traits\TracksImportStats;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Mtc\MercuryDataModels\ApiNotification;

/**
 * Stock provider for import maps configured with source_type = http_json.
 *
 * Runs alongside the existing file-based App\Modules\Stock\ImportMap
 * orchestrator without modifying it. Both are registered as stock
 * providers; each owns its own source type and only processes maps
 * matching that type.
 *
 * Row processing is delegated to VehicleImport so the file and
 * http_json paths share identical mapping/processing behaviour
 * (including taxonomies, attribute writes, image sync, and end-of-run
 * additional tasks). The only difference between the two orchestrators
 * is the source of rows.
 */
class HttpJsonImportMap implements StockProvider
{
    use TracksImportStats;

    public const SOURCE_TYPE = 'http_json';

    public function __construct(
        private readonly ImportMapSourceFactory $sourceFactory = new ImportMapSourceFactory(),
    ) {
    }

    public function enabled(): bool
    {
        return Settings::get('stock-file-enabled') ?? false;
    }

    public function name(): string
    {
        return 'HTTP/JSON import map';
    }

    public function runScheduledImport(bool $fullSync = true): void
    {
        $this->resetStats();
        foreach ($this->loadImportMaps() as $map) {
            try {
                $this->runForMap($map);
                Event::dispatch(new StockSyncFinished('import-map-' . $map->id));
            } catch (\Throwable $exception) {
                Log::error(
                    'Failed to run http_json import map ' . $map->name . ' for ' . tenant('id'),
                    [$exception->getMessage()],
                );
            }
        }
    }

    public function runForMap(ImportMapModel $map): void
    {
        $startedAt = microtime(true);

        $importer = new VehicleImport($map->id)
            ->setImportMap($map, true)
            ->setAdditionalTasks($map->data['automations'] ?? []);

        $rows = $this->collectRows($map);
        $importer->collection($rows);

        $stats = $importer->getImportStats();
        $this->aggregateStats($stats);

        $this->recordRunNotification($map, [
            'url' => $map->data['http']['url'] ?? null,
            'array_path' => $map->data['http']['array_path'] ?? null,
            'rows_fetched' => $rows->count(),
            'duration_ms' => (int) round((microtime(true) - $startedAt) * 1000),
            'stats' => $stats,
        ]);
    }

    private function recordRunNotification(ImportMapModel $map, array $payload): void
    {
        try {
            ApiNotification::query()->create([
                'provider' => 'import-map-' . $map->id,
                'reference' => (string) $map->id,
                'processed' => true,
                'data_model' => 'vehicle',
                'data' => $payload,
            ]);
        } catch (\Throwable $exception) {
            Log::warning("HttpJsonImportMap: failed to record api_notification for map [{$map->id}]", [
                'tenant_id' => tenant('id'),
                'error' => $exception->getMessage(),
            ]);
        }
    }

    private function collectRows(ImportMapModel $map): Collection
    {
        $source = $this->sourceFactory->for($map);

        $rows = collect();
        foreach ($source->fetch($map) as $row) {
            $rows->push(collect($row));
        }
        return $rows;
    }

    private function loadImportMaps(): Collection
    {
        return ImportMapModel::query()
            ->get()
            ->filter(fn (ImportMapModel $map) => !empty($map->data['automate']))
            ->filter(fn (ImportMapModel $map) => ($map->data['source_type'] ?? null) === self::SOURCE_TYPE);
    }

    private function aggregateStats(array $stats): void
    {
        for ($i = 0; $i < $stats['created']; $i++) {
            $this->incrementCreated();
        }
        for ($i = 0; $i < $stats['updated']; $i++) {
            $this->incrementUpdated();
        }
        for ($i = 0; $i < $stats['failed']; $i++) {
            $this->incrementFailed();
        }
    }
}
