<?php

namespace App\Http\Controllers;

use App\Enums\ParticipateStatus;
use App\Http\Requests\StoreHuntStepRequest;
use App\Models\Hunts;
use App\Models\HuntSteps;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class HuntStepsController extends Controller
{
    public function store(StoreHuntStepRequest $request, Hunts $hunt): JsonResponse
    {
        if ($hunt->creator_id !== auth()->id()) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $step = $hunt->steps()->create($request->validated());

        return response()->json($step, 201);
    }

    public function validateStep(Request $request, Hunts $hunt, HuntSteps $step): JsonResponse
    {
        $validated = $request->validate([
            'latitude' => 'required|numeric',
            'longitude' => 'required|numeric',
        ]);

        $user = $request->user();

        if ((int) $step->hunt_id !== (int) $hunt->id) {
            return response()->json(['message' => 'Step does not belong to this hunt'], 404);
        }

        $participation = $user->participations()->where('hunt_id', $hunt->id)->first();

        if (! $participation) {
            return response()->json(['message' => 'Not participating in this hunt'], 403);
        }

        if ($participation->pivot->status !== ParticipateStatus::InProgress->value) {
            return response()->json(['message' => 'Hunt is joined but not started'], 409);
        }

        if ((int) $participation->pivot->current_step_number !== (int) $step->step_number) {
            return response()->json(['message' => 'This is not your current step'], 400);
        }

        $distance = $this->distanceMeters(
            (float) $validated['latitude'],
            (float) $validated['longitude'],
            (float) $step->latitude,
            (float) $step->longitude,
        );

        if ($distance > $step->radius_m) {
            return response()->json([
                'success' => false,
                'message' => 'You are too far from the target.',
                'distance_m' => round($distance),
                'radius_m' => $step->radius_m,
            ], 400);
        }

        $nextStepNumber = (int) $step->step_number + 1;
        $nextStep = $hunt->steps()->where('step_number', $nextStepNumber)->first();

        $updateData = [];

        if ($nextStep) {
            $updateData['current_step_number'] = $nextStepNumber;
        } else {
            $updateData['current_step_number'] = $nextStepNumber;
            $updateData['status'] = ParticipateStatus::Completed->value;
        }

        $hunt->participants()->updateExistingPivot($user->id, $updateData);

        $response = [
            'success' => true,
            'message' => 'Step validated',
            'revealed_hint' => [
                'title' => $step->title,
                'hint_text' => $step->hint_text,
                'hint_media_url' => $step->hint_media_url,
            ],
        ];

        if ($nextStep) {
            $response['next_step'] = $this->stepTargetPayload($nextStep);
        } else {
            $response['message'] = 'Hunt completed';
            $response['completed'] = true;
        }

        return response()->json($response);
    }

    /**
     * @return array<string, mixed>
     */
    private function stepTargetPayload(HuntSteps $step): array
    {
        return [
            'id' => $step->id,
            'hunt_id' => $step->hunt_id,
            'step_number' => $step->step_number,
            'title' => $step->title,
            'latitude' => $step->latitude,
            'longitude' => $step->longitude,
            'radius_m' => $step->radius_m,
            'ar_model' => 'chest',
        ];
    }

    private function distanceMeters(float $latitudeFrom, float $longitudeFrom, float $latitudeTo, float $longitudeTo): float
    {
        $earthRadius = 6371000;

        $latFrom = deg2rad($latitudeFrom);
        $lonFrom = deg2rad($longitudeFrom);
        $latTo = deg2rad($latitudeTo);
        $lonTo = deg2rad($longitudeTo);

        $latDelta = $latTo - $latFrom;
        $lonDelta = $lonTo - $lonFrom;

        $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
            cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));

        return $angle * $earthRadius;
    }
}
