<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreImportMap;
use App\Http\Requests\UpdateImportMap;
use App\Http\Resources\ImportMapResource;
use App\ImportMaps\VehicleImportMap;
use App\IntegrationRepository;
use App\Models\ImportMap;
use Box\Spout\Common\Entity\Cell;
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use App\Facades\Settings;

class ImportMapController extends Controller
{
    public function index()
    {
        return ImportMap::query()->paginate();
    }

    public function store(StoreImportMap $request): ImportMapResource
    {
        return new ImportMapResource(ImportMap::query()
            ->create([
                'name' => $request->input('name'),
                'type' => $request->input('type'),
            ]));
    }

    public function show(ImportMap $importMap): ImportMapResource
    {
        return new ImportMapResource($importMap);
    }

    public function update(UpdateImportMap $request, ImportMap $importMap): ImportMapResource
    {
        $data = $request->input('data') ?? [];
        $data['has_header_row'] = $request->input('has_header_row');
        $data['clear_previous_entries'] = $request->input('clear_previous_entries');
        $data['remove_from_remote'] = $request->input('remove_from_remote');
        $data['extra_fields'] = collect($data['extra_fields'] ?? [])
            ->filter(fn($row) => !empty($row['on_model']))
            ->toArray();
        $importMap->update([
            'name' => $request->input('name'),
            'data' => $data,
        ]);
        foreach ($request->input('fields') as $field) {
            if (empty($field['on_file']) && $field['on_file'] !== '0') {
                continue;
            }
            $data = $field['data'] ?? [];
            $data['required_to_import'] = !empty($field['required_to_import']);
            $data['save_on_update'] = !empty($field['save_on_update']);
            $castRestriction = $this->getCastRestriction($importMap, $field['on_model']);
            if ($castRestriction) {
                $data['cast_type'] = $castRestriction;
            }
            $importMap->fields()
                ->updateOrCreate([
                    'on_file' => $field['on_file'],
                ], [
                    'on_model' => $field['on_model'],
                    'default_value' => $field['default_value'],
                    'is_images' => $field['on_model'] === 'mediaUses',
                    'is_list' => $field['is_list'],
                    'list_separator' => $field['list_separator'],
                    'data' => $data,
                ]);
        }
        $extraFieldIds = collect($request->input('data.extra_fields', []))
            ->pluck('id')
            ->filter()
            ->values();
        $importMap->fields()
            ->where('data->is_static', true)
            ->whereNotIn('on_file', $extraFieldIds)
            ->delete();
        foreach ($request->input('data.extra_fields') as $field) {
            if (empty($field['on_model'])) {
                continue;
            }
            $data = $field['data'] ?? [];
            $data['is_static'] = true;
            $data['save_on_update'] = !empty($field['save_on_update']);
            $castRestriction = $this->getCastRestriction($importMap, $field['on_model']);
            if ($castRestriction) {
                $data['cast_type'] = $castRestriction;
            }
            $importMap->fields()
                ->updateOrCreate([
                    'on_file' => $field['id'],
                ], [
                    'on_model' => $field['on_model'],
                    'default_value' => $field['default_value'] ?? null,
                    'is_images' => $field['on_model'] === 'mediaUses',
                    'is_list' => $field['is_list'] ?? false,
                    'list_separator' => $field['list_separator'] ?? null,
                    'data' => $data,
                ]);
        }

        if ($data['automate'] ?? false) {
            Settings::update('stock-file-enabled', true);
        }

        return new ImportMapResource($importMap);
    }

    public function upload(Request $request, ImportMap $importMap)
    {
        $data = $importMap->data ?? [];

        $request->file('file')->storeAs($request->file('file')->getClientOriginalName());
        $reader = ReaderEntityFactory::createReaderFromFile($request->file('file')->getClientOriginalName());
        $reader->open($request->file('file'));
        foreach ($reader->getSheetIterator() as $sheet) {
            foreach ($sheet->getRowIterator() as $index => $row) {
                if ($index == 1) {
                    if ($request->input('has_header_row')) {
                        $header_columns = collect($row->getCells())
                            ->map(fn(Cell $cell) => Str::slug($cell->getValue(), '_'));
                    } else {
                        $header_columns = collect($row->getCells())
                            ->map(fn(Cell $cell, $index) => $index);
                    }
                    Log::debug('header row', [$header_columns]);
                } else {
                    $data['row_data'] = collect($row->getCells())
                        ->keyBy(fn($cell, $index) => $header_columns[$index] ?? $index)
                        ->map(fn(Cell $cell) => $cell->getValue())
                        ->toArray();
                }
                if ($index > 2) {
                    break;
                }
            }
        }

        $importMap->update([
            'data' => $data
        ]);

        $importMap->fields()
            ->whereNotIn('on_file', array_keys($data['row_data']))
            ->delete();

        foreach ($data['row_data'] as $column => $value) {
            $importMap->fields()->updateOrCreate([
                'on_file' => $column
            ]);
        }
        return new ImportMapResource($importMap);
    }

    public function download(ImportMap $importMap, $file)
    {
        $disk = Storage::build([
            'driver' => $importMap['data']['protocol'],
            'root' => $importMap['data']['file_root'] ?? null,
            'host' => $importMap['data']['host'],
            'username' => $importMap['data']['username'],
            'password' => $importMap['data']['password'],
            'throw' => false,
        ]);

        return $disk->download($file, basename((string) $file), [
            'Content-Type' => $disk->mimeType($file),
        ]);
    }

    public function destroy(ImportMap $importMap)
    {
        $importMap->delete();

        return response('ok');
    }

    public function getForModel(string $model): Response
    {
        return response([
            'automations' => $this->getImportAutomations($model),
            'types' => ImportMap::query()
                ->where('type', $model)
                ->select('id', 'name')
                ->get()
                ->prepend([
                    'id' => 'default',
                    'name' => 'Autonomy import file'
                ])
        ]);
    }

    private function getCastRestriction(ImportMap $importMap, ?string $field): ?string
    {
        if (empty($field)) {
            return null;
        }

        return match ($importMap->type) {
            'vehicle' => (new VehicleImportMap())->castRestrictions($field),
            default => null,
        };
    }

    private function getImportAutomations(string $model)
    {
        if ($model == 'vehicle') {
            return new IntegrationRepository()->getAutomationsForVehicle();
        }
        return [];
    }
}
