<?php

namespace App\Http\Controllers\Gis;

use App\Http\Controllers\Controller;
use App\Models\GIS\GisFeatureCollection;
use App\Traits\GisTrait;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;

class GisCollectionController extends Controller
{
    use GisTrait;

    /**
     * List all GIS collections
     */
    public function index(): JsonResponse
    {
        try {
            $collections = GisFeatureCollection::all(['uuid', 'name', 'description']);
            return response()->json([
                'status' => 'success',
                'data' => $collections,
                'message' => 'Fetched collections successfully',
            ], 200);
        } catch (\Exception $e) {
            return $this->errorResponse($e, 'Error fetching collections');
        }
    }

    /**
     * Show a collection or a single feature inside it
     */
    public function show(Request $request, $identifier): JsonResponse
    {
        try {
            // Validate identifier (must be non-empty string)
            $validator = Validator::make(['identifier' => $identifier], [
                'identifier' => ['required', 'string', 'max:255'],
            ]);

            if ($validator->fails()) {
                return response()->json([
                    'status' => 'error',
                    'data' => null,
                    'message' => 'Invalid collection identifier',
                    'errors' => $validator->errors(),
                ], 422);
            }

            // Optional feature UUID parameter validation
            $featureUuid = $request->query('feature_uuid');
            if ($featureUuid) {
                $featureValidator = Validator::make(['feature_uuid' => $featureUuid], [
                    'feature_uuid' => ['required', 'uuid'],
                ]);

                if ($featureValidator->fails()) {
                    return response()->json([
                        'status' => 'error',
                        'data' => null,
                        'message' => 'Invalid feature UUID',
                        'errors' => $featureValidator->errors(),
                    ], 422);
                }
            }

            // Find collection by UUID or name
            $collection = GisFeatureCollection::where('uuid', $identifier)
                ->orWhere('name', $identifier)
                ->firstOrFail();

            if ($featureUuid) {
                // Fetch single feature
                $feature = $collection->features()
                    ->with('properties', 'geometries')
                    ->where('uuid', $featureUuid)
                    ->first();

                if (!$feature) {
                    return response()->json([
                        'status' => 'error',
                        'data' => null,
                        'message' => 'Feature not found in this collection',
                    ], 404);
                }

                $data = [
                    'collection' => $collection->name,
                    'features' => [
                        [
                            'id' => $feature->uuid,
                            'type' => 'Feature',
                            'active' => $feature->active,
                            'hide' => $feature->hide,
                            'zoom' => $feature->zoom,
                            'properties' => $feature->properties->pluck('value', 'name'),
                            'coordinates' => $this->formatCoordinates($feature->geometries),
                        ],
                    ],
                ];
            } else {
                // Fetch all features
                $collection->load('features.properties', 'features.geometries');

                $features = $collection->features->map(function ($feature) {
                    $coords = $feature->geometries->map(fn($geo) => json_decode($geo->coordinates,
                        true))->flatten(1);
                    return [
                        'id' => $feature->uuid,
                        'type' => 'Feature',
                        'active' => $feature->active,
                        'hide' => $feature->hide,
                        'zoom' => $feature->zoom,
                        'properties' => $feature->properties->pluck('value', 'name'),
                        'coordinates' => $coords,
                    ];
                });

                $data = [
                    'collection' => $collection->name,
                    'features' => $features,
                ];
            }

            return response()->json([
                'status' => 'success',
                'data' => $data,
                'message' => 'Fetched collection successfully',
            ], 200);

        } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
            return response()->json([
                'status' => 'error',
                'data' => null,
                'message' => 'Collection not found',
            ], 404);
        } catch (\Exception $e) {
            return $this->errorResponse($e, 'Error fetching collection');
        }
    }

    public function setHide(Request $request, string $uuid): JsonResponse
    {
        $request->validate([
            'hide' => 'required|boolean',
        ]);

        try {
            // Find the collection by UUID
            $collection = GisFeatureCollection::where('uuid', $uuid)->firstOrFail();

            // Set hide value explicitly
            $collection->hide = $request->input('hide');
            $collection->save();

            return response()->json([
                'status' => 'success',
                'uuid' => $collection->uuid,
                'hide' => $collection->hide,
                'message' => $collection->hide ? 'Collection is now hidden' : 'Collection is now visible',
            ], 200);

        } catch (\Exception $e) {
            return response()->json([
                'status' => 'error',
                'message' => 'Error updating hide status: ' . $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Store a new collection or import GIS JSON
     */
    public function store(Request $request): JsonResponse
    {
        try {
            $jsonData = $request->json()->all();

            // If a single collection object is sent, wrap it in an array
            if (isset($jsonData['feature']) && isset($jsonData['data'])) {
                $jsonData = [$jsonData];
            }

            if ($this->isGisJsonArray($jsonData)) {
                return $this->importGisJson($jsonData);
            }

            // Regular collection creation via form
            $request->validate([
                'name' => 'required|string|unique:gis_feature_collections,name',
                'description' => 'nullable|string',
            ]);

            $collection = GisFeatureCollection::create([
                'uuid' => (string)Str::uuid(),
                'name' => $request->name,
                'description' => $request->description,
            ]);

            return response()->json([
                'status' => 'success',
                'data' => $collection,
                'message' => 'Collection created successfully',
            ], 201);
        } catch (\Exception $e) {
            return $this->errorResponse($e, 'Error creating collection');
        }
    }

    /**
     * Update collection info or import GIS JSON
     */
    public function update(Request $request, GisFeatureCollection $collection): JsonResponse
    {
        try {
            if ($this->isGisJson($request)) {
                $jsonData = $request->json()->all();
                $jsonData = array_map(fn($cData) => array_merge($cData, ['feature' => $collection->name]),
                    $jsonData);
                return $this->updateGisData($collection, $jsonData);
            }

            $request->validate([
                'name' => "required|string|unique:gis_feature_collections,name,{$collection->uuid},uuid",
                'description' => 'nullable|string',
            ]);

            $collection->update($request->only(['name', 'description']));
            $collection->load('features.properties', 'features.geometries');

            return response()->json([
                'status' => 'success',
                'data' => $this->formatCollectionResponse($collection),
                'message' => 'Collection updated successfully',
            ], 200);
        } catch (\Exception $e) {
            return $this->errorResponse($e, 'Error updating collection');
        }
    }

    /**
     * Delete a collection with all features
     */
    public function destroy(GisFeatureCollection $collection): JsonResponse
    {
        try {
            DB::transaction(function () use ($collection) {
                foreach ($collection->features as $feature) {
                    $feature->properties()->delete();
                    $feature->geometries()->delete();
                }
                $collection->features()->delete();
                $collection->delete();
            });

            return response()->json([
                'status' => 'success',
                'data' => null,
                'message' => 'Collection deleted successfully',
            ], 200);
        } catch (\Exception $e) {
            return $this->errorResponse($e, 'Error deleting collection');
        }
    }
}
