<?php

namespace App\Http\Resources;

use App\Events\LoadDealershipDataFields;
use App\ImportMaps\VehicleImportMap;
use App\Models\ImportCondition;
use App\Modules\Stock\ImportMapSources\ImportMapSourceFactory;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;

class ImportMapResource extends JsonResource
{
    public static $wrap = '';

    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    #[\Override]
    public function toArray(Request $request): array
    {
        $this->resource->load('fields');
        $this->resource->row_data = collect($this->resource->data['row_data'] ?? [])->keys();
        $this->resource->data_options = collect($this->getFieldsForType())
                ->map(fn ($value, $key) => [
                    'id' => $key,
                    'name' => "$value ($key) ",
                    'cast_restriction' => $this->getCastRestrictions($key),
                ])
                ->values();
        $resource = $this->resource->toArray();
        $resource['has_header_row'] = $this->resource->data['has_header_row'] ?? true;
        $resource['clear_previous_entries'] = $this->resource->data['clear_previous_entries'] ?? false;
        $resource['remove_from_remote'] = $this->resource->data['remove_from_remote'] ?? false;
        $resource['fields'] = $this->mapFields();
        $resource['remote_protocols'] = [
            ['value' => 'ftp', 'label' => 'FTP'],
            ['value' => 'sftp', 'label' => 'SFTP'],
        ];
        $resource['source_types'] = ImportMapSourceFactory::availableTypes();
        $resource['schedule_options'] = [
            ['value' => 'daily', 'label' => 'Daily'],
            ['value' => 'twice_daily', 'label' => 'Twice Daily'],
            ['value' => 'every_two_hours', 'label' => 'Every 2 hours'],
            ['value' => 'hourly', 'label' => 'Hourly'],
        ];
        $resource['dealership_fields'] = $this->getDealershipFields();
        $resource['data']['source_type'] ??= ImportMapSourceFactory::DEFAULT_SOURCE_TYPE;
        $resource['data']['update_only'] ??= false;
        $resource['data']['http'] ??= ['url' => '', 'headers' => [], 'array_path' => '', 'latest_by' => ''];
        $resource['data']['extra_fields'] = $this->mapExtraFields($resource['data']['extra_fields'] ?? []);
        $resource['data']['automations'] ??= [];
        $resource['remote_files'] = $this->loadRemoteFiles();
        $resource['active_import_conditions'] = ImportCondition::query()
            ->where('provider', 'import-map')
            ->where('active', 1)
            ->where(fn ($query) => $query->whereNull('import_map_id')
                ->orWhere('import_map_id', $this->resource->id))
            ->get();
        return $resource;
    }

    private function getFieldsForType(): array
    {
        return match ($this->resource->type) {
            'vehicle' => new VehicleImportMap()->columns(),
            default => [],
        };
    }
    private function getCastRestrictions($key): ?string
    {
        return match ($this->resource->type) {
            'vehicle' => new VehicleImportMap()->castRestrictions($key),
            default => null,
        };
    }

    private function getDealershipFields()
    {
        return collect(event(new LoadDealershipDataFields()))
            ->filter()
            ->mapWithKeys(fn ($field) => $field)
            ->map(function ($field, $key) {
                $field['id'] = $key;
                return $field;
            })
            ->prepend(['id' => 'location_stock', 'label' => 'Stock location'])
            ->prepend(['id' => 'id', 'label' => 'Dealership ID'])
            ->values();
    }

    private function mapFields(): Collection
    {
        return $this->resource->fields->keyBy('on_file')
            ->map(function ($field) {
                $field['edit'] = false;
                $field['required_to_import'] = $field['data']['required_to_import'] ?? false;
                $field['save_on_update'] = $field['data']['save_on_update'] ?? true;
                $field['is_match_key'] = (bool) ($field['is_match_key'] ?? false);
                if (!isset($field['data'])) {
                    $field['data'] = [];
                }
                return $field;
            });
    }

    private function mapExtraFields(array $extraFields = []): array
    {
        return collect($extraFields)
            ->map(function ($extraField) {
                $extraField['edit'] = false;
                $extraField['save_on_update'] ??= true;
                return $extraField;
            })
            ->toArray();
    }

    private function loadRemoteFiles(): Collection
    {
        if (empty($this->resource->data['automate'])) {
            return collect();
        }

        try {
            $disk = Storage::build([
                'driver' => $this->resource['data']['protocol'],
                'root' => $this->resource['data']['file_root'] ?? null,
                'host' => $this->resource['data']['host'],
                'username' => $this->resource['data']['username'],
                'password' => $this->resource['data']['password'],
                'throw' => false,
                'timeout' => 2,
            ]);

            return collect($disk->files())
                ->map(fn ($file) => [
                    'name' => $file,
                    'size' => $this->fileSize($disk, $file),
                ]);
        } catch (\Exception) {
            return collect();
        }
    }

    private function fileSize($disk, string $file): string
    {
        $kb = $disk->size($file) / 1024;
        if ($kb < 1024) {
            return round($kb) . 'KiB';
        }

        return round($kb / 1024, 1) . 'MiB';
    }
}
