<?php

namespace App\Console\Commands;

use App\Models\City;
use Illuminate\Console\Command;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use function Symfony\Component\String\b;

class ExtractGeometryForCities extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:extract-geometry-for-cities {jsonPath}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'This command will extract polygons for cities from the given .json file';

    /**
     * Execute the console command.
     * @throws FileNotFoundException
     */
    public function handle(): int
    {
        $jsonPath = $this->argument('jsonPath');

        $json = File::get($jsonPath);
        $data = json_decode($json, true);

        $features = $data['features'] ?? null;
        if ($features === null) {
            $this->error('No features were found');
            return parent::FAILURE;
        }

        foreach ($data['features'] as $city) {

            $cityId = $city['properties']['city_id'] ?? null;
            if ($cityId === null)
            {
                $this->info("this city doesn't have id: $city");
                continue;
            }

            $coordinates = $city['geometry']['coordinates'] ?? null;
            if ($coordinates === null)
            {
                $this->info("this city doesn't have coordinates: $coordinates");
                continue;
            }

            $type = $city['geometry']['type'] ?? null;
            if ($type === null)
            {
                $this->info("This city doesn't have a type: $city");
                continue;
            }

            try {
                switch ($type) {

                    case 'Polygon':
                        $wktCoords = collect($coordinates[0])
                            ->map(fn($pair) => $pair[1] . ' ' . $pair[0])
                            ->implode(',');
                        $wellKnownText = "POLYGON(($wktCoords))";
                        break;

                    case 'MultiPolygon':
                        $wktCoords = collect($coordinates)
                            ->map(function ($polygon) {
                                $rings = collect($polygon)->map(function ($ring) {
                                    if ($ring[0] !== end($ring)) {
                                        $ring[] = $ring[0];
                                    }
                                    return collect($ring)
                                        ->map(fn($pair) => $pair[1] . ' ' . $pair[0])
                                        ->implode(',');
                                });
                                return '((' . $rings->implode('),(') . '))';
                            })
                            ->implode(',');

                        $wellKnownText = "MULTIPOLYGON($wktCoords)";
                        break;

                    default:
                        $this->info("$type is not a valid type in city: $city");
                        continue 2;
                }
            }
            catch (\Throwable $th)
            {
                $this->error("Something went wrong: $th");
                continue;
            }

            $query = City::query()
                ->find($cityId);

            if (!$query) {
                $this->info("City $cityId not found");
                continue;
            }

            try {
                $query->update([
                    'geometry' => DB::raw("ST_GeomFromText('$wellKnownText', 4326)")
                ]);
            }
            catch (\Throwable $th)
            {
                $this->error("Something went wrong: $th");
            }
        }

        return parent::SUCCESS;
    }
}
