<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Services\FishScore\Contracts\CoastlineServiceInterface;
use App\Services\FishScore\FeatureCalculator;
use App\Services\FishScore\FishScoreEngine;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;

class FishScoreController extends Controller
{
    public function __construct(
        private FishScoreEngine $scoreEngine,
        private CoastlineServiceInterface $coastline,
    ) {}

    /**
     * Tek nokta skor + gerekçe.
     * GET /api/fish/score?lat=&lon=&species=&time=&region=
     */
    public function score(Request $request): JsonResponse
    {
        $request->validate([
            'lat' => 'required|numeric|between:-90,90',
            'lon' => 'required|numeric|between:-180,180',
            'species' => 'required|integer|exists:species,id',
            'time' => 'nullable|date',
            'region' => 'nullable|string|in:ege,marmara,akdeniz,karadeniz',
        ]);

        $lat = (float) $request->lat;
        $lon = (float) $request->lon;

        if ($this->coastline->isSea($lat, $lon) === false) {
            return response()->json([
                'message' => 'Bu koordinat kara üzerinde; deniz skoru hesaplanamaz.',
                'error' => 'land_point',
            ], 422);
        }

        $time = $request->time ? Carbon::parse($request->time) : Carbon::now();

        $result = $this->scoreEngine->calculateScore(
            lat: $lat,
            lon: $lon,
            speciesId: (int) $request->species,
            time: $time,
            region: $request->region,
        );

        return response()->json([
            'final_score' => $result->finalScore,
            'label' => $result->label(),
            'label_tr' => $result->labelTr(),
            'habitat_score' => $result->habitatScore,
            'dynamic_modifier' => round($result->dynamicModifier, 2),
            'prey_multiplier' => round($result->preyMultiplier, 2),
            'explanations' => $result->explanations,
            'sub_scores' => $result->subScores,
        ]);
    }

    /**
     * Tüm türler için bir noktadaki skorları döndürür.
     * GET /api/fish/scores-at-point?lat=&lon=&time=&region=
     */
    public function scoresAtPoint(Request $request): JsonResponse
    {
        $request->validate([
            'lat' => 'required|numeric|between:-90,90',
            'lon' => 'required|numeric|between:-180,180',
            'time' => 'nullable|date',
            'region' => 'nullable|string|in:ege,marmara,akdeniz,karadeniz',
        ]);

        $lat = (float) $request->lat;
        $lon = (float) $request->lon;

        if ($this->coastline->isSea($lat, $lon) === false) {
            return response()->json([
                'data' => [],
                'meta' => [
                    'land_point' => true,
                    'message' => 'Bu koordinat kara üzerinde; deniz skoru listelenmez.',
                ],
            ]);
        }

        $time = $request->time ? Carbon::parse($request->time) : Carbon::now();

        $results = $this->scoreEngine->calculateScoresForPoint(
            lat: $lat,
            lon: $lon,
            time: $time,
            region: $request->region,
        );

        return response()->json(['data' => $results]);
    }

    /**
     * Ham özellik değerleri (debug/şeffaflık).
     * GET /api/fish/features?lat=&lon=&time=
     */
    public function features(Request $request): JsonResponse
    {
        $request->validate([
            'lat' => 'required|numeric|between:-90,90',
            'lon' => 'required|numeric|between:-180,180',
            'time' => 'nullable|date',
        ]);

        $time = $request->time ? Carbon::parse($request->time) : Carbon::now();

        $featureCalc = app(FeatureCalculator::class);
        $static = $featureCalc->getStaticFeatures((float) $request->lat, (float) $request->lon);
        $dynamic = $featureCalc->getDynamicFeatures((float) $request->lat, (float) $request->lon, $time);

        return response()->json([
            'static_features' => $static,
            'dynamic_features' => $dynamic,
            'time' => $time->toIso8601String(),
            'land_point' => $this->coastline->isSea((float) $request->lat, (float) $request->lon) === false,
        ]);
    }

    /**
     * Birden fazla nokta için tek tür skoru (batch — heatmap için).
     * POST /api/fish/scores-grid
     * Kara noktaları ve geçersiz derinlik maskelenir.
     */
    public function scoresGrid(Request $request): JsonResponse
    {
        $request->validate([
            'species_id' => 'required|integer|exists:species,id',
            'points' => 'required|array|min:1|max:50',
            'points.*.lat' => 'required|numeric|between:-90,90',
            'points.*.lon' => 'required|numeric|between:-180,180',
            'time' => 'nullable|date',
            'region' => 'nullable|string|in:ege,marmara,akdeniz,karadeniz',
        ]);

        $time = $request->time ? Carbon::parse($request->time) : Carbon::now();
        $speciesId = (int) $request->species_id;
        $region = $request->region;

        $ttl = (int) config('fish.cache_scores_grid_ttl', 0);
        if ($ttl > 0) {
            $cacheKey = 'fish:scores-grid:v1:'.md5(json_encode([
                $speciesId,
                $request->points,
                $time->timestamp,
                $region,
            ]));

            $data = Cache::remember($cacheKey, $ttl, fn () => $this->buildScoresGridPayload(
                $request->points,
                $speciesId,
                $time,
                $region
            ));

            return response()->json(['data' => $data]);
        }

        return response()->json([
            'data' => $this->buildScoresGridPayload($request->points, $speciesId, $time, $region),
        ]);
    }

    /**
     * @param  array<int, array{lat: mixed, lon: mixed}>  $points
     * @return array<int, array{lat: float, lon: float, score: int, label: string, label_tr: string}>
     */
    private function buildScoresGridPayload(array $points, int $speciesId, Carbon $time, ?string $region): array
    {
        $featureCalc = app(FeatureCalculator::class);
        $results = [];

        foreach ($points as $point) {
            $lat = (float) $point['lat'];
            $lon = (float) $point['lon'];

            if ($this->coastline->isSea($lat, $lon) === false) {
                continue;
            }

            $static = $featureCalc->getStaticFeatures($lat, $lon);
            $depth = $static['depth_m'] ?? null;
            if ($depth === null || (float) $depth <= 0) {
                continue;
            }

            $result = $this->scoreEngine->calculateScore(
                lat: $lat,
                lon: $lon,
                speciesId: $speciesId,
                time: $time,
                region: $region,
            );

            $results[] = [
                'lat' => $lat,
                'lon' => $lon,
                'score' => $result->finalScore,
                'label' => $result->label(),
                'label_tr' => $result->labelTr(),
            ];
        }

        return $results;
    }
}
