<?php
// app/Helpers/OngkirHelper.php

namespace App\Helpers;

use Illuminate\Support\Facades\Log;

class OngkirHelper
{
    // -------------------------------------------------------
    // TARIF JARAK — minimal 1 km (dibulatkan ke atas)
    // -------------------------------------------------------
    const TARIF_PER_KM = 1000; // Rp 1.000/km

    // -------------------------------------------------------
    // TARIF PROVINSI
    // -------------------------------------------------------
    const TARIF_SAMA_PROVINSI = 2000; // Rp 2.000 sama provinsi
    const TARIF_BEDA_PROVINSI = 5000; // Rp 5.000 beda provinsi

    // -------------------------------------------------------
    // TARIF BERAT
    // -------------------------------------------------------
    const TARIF_BERAT_RINGAN = 2000; // < 500 gram
    const TARIF_BERAT_BERAT  = 3000; // >= 500 gram

    // ===================================================
    // CEK KOORDINAT VALID
    // ===================================================
    public static function koordinatValid($lat, $lng): bool
    {
        if ($lat === null || $lng === null) return false;
        $lat = (float) $lat;
        $lng = (float) $lng;
        // 0,0 dianggap tidak valid (nilai default kosong)
        if (abs($lat) < 0.0001 && abs($lng) < 0.0001) return false;
        if ($lat < -90  || $lat > 90)  return false;
        if ($lng < -180 || $lng > 180) return false;
        return true;
    }

    // ===================================================
    // HITUNG JARAK HAVERSINE (km)
    // ===================================================
    public static function hitungJarak(float $lat1, float $lng1, float $lat2, float $lng2): float
    {
        $R    = 6371;
        $dLat = deg2rad($lat2 - $lat1);
        $dLng = deg2rad($lng2 - $lng1);
        $a    = sin($dLat / 2) ** 2
              + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLng / 2) ** 2;
        return $R * 2 * atan2(sqrt($a), sqrt(1 - $a));
    }

    // ===================================================
    // BIAYA JARAK
    // Minimal dihitung 1 km — tidak ada jarak gratis
    // ===================================================
    public static function hitungBiayaJarak(float $jarakKm): int
    {
        // Minimal 1 km, lalu bulatkan ke atas
        $km = max(1, (int) ceil($jarakKm));
        return $km * self::TARIF_PER_KM;
    }

    // ===================================================
    // BIAYA BERAT
    // ===================================================
    public static function hitungBiayaBerat(float $beratGram): int
    {
        return $beratGram < 500 ? self::TARIF_BERAT_RINGAN : self::TARIF_BERAT_BERAT;
    }

    // ===================================================
    // BIAYA PROVINSI
    // ===================================================
    public static function hitungBiayaProvinsi(string $provinsiToko, string $provinsiUser): array
    {
        $toko = strtoupper(trim($provinsiToko));
        $user = strtoupper(trim($provinsiUser));

        if ($toko !== '' && $toko === $user) {
            return ['tarif' => self::TARIF_SAMA_PROVINSI, 'kategori' => 'Sama Provinsi'];
        }
        return ['tarif' => self::TARIF_BEDA_PROVINSI, 'kategori' => 'Beda Provinsi'];
    }

    // ===================================================
    // HITUNG BERDASARKAN JARAK (koordinat tersedia)
    // Total = biaya_jarak + biaya_provinsi + biaya_berat
    // ===================================================
    public static function hitungBerdasarkanJarak(
        float  $tokoLat,
        float  $tokoLng,
        float  $userLat,
        float  $userLng,
        string $namaProvinsiToko,
        string $namaProvinsiUser,
        float  $beratGram = 0
    ): array {
        $jarakKm          = self::hitungJarak($tokoLat, $tokoLng, $userLat, $userLng);
        $jarakDihitung    = max(1, (int) ceil($jarakKm)); // minimal 1 km
        $biayaJarak       = $jarakDihitung * self::TARIF_PER_KM;
        $biayaBerat       = self::hitungBiayaBerat($beratGram);
        $provinsiData     = self::hitungBiayaProvinsi($namaProvinsiToko, $namaProvinsiUser);
        $biayaProvinsi    = $provinsiData['tarif'];
        $kategoriProvinsi = $provinsiData['kategori'];

        $totalOngkir = $biayaJarak + $biayaProvinsi + $biayaBerat;

        $detail = [];
        $detail[] = sprintf(
            'Jarak: %s km (min. %d km) x Rp %s = Rp %s',
            round($jarakKm, 1),
            $jarakDihitung,
            number_format(self::TARIF_PER_KM, 0, ',', '.'),
            number_format($biayaJarak, 0, ',', '.')
        );
        $detail[] = sprintf(
            'Provinsi (%s): Rp %s',
            $kategoriProvinsi,
            number_format($biayaProvinsi, 0, ',', '.')
        );
        $detail[] = sprintf(
            'Berat: %s gram (%s) = Rp %s',
            number_format($beratGram, 0, ',', '.'),
            $beratGram < 500 ? '< 500 gram' : '>= 500 gram',
            number_format($biayaBerat, 0, ',', '.')
        );

        $detailText = implode(' + ', $detail)
            . sprintf(' = Rp %s', number_format($totalOngkir, 0, ',', '.'));

        return [
            'ongkir'            => $totalOngkir,
            'jarak_km'          => round($jarakKm, 1),
            'jarak_dihitung_km' => $jarakDihitung,
            'biaya_jarak'       => $biayaJarak,
            'biaya_provinsi'    => $biayaProvinsi,
            'biaya_berat'       => $biayaBerat,
            'kategori'          => $kategoriProvinsi . ' (berdasarkan jarak)',
            'kategori_provinsi' => $kategoriProvinsi,
            'detail'            => $detailText,
            'menggunakan_jarak' => true,
            'rincian' => [
                'jarak'          => $jarakKm,
                'jarak_dihitung' => $jarakDihitung,
                'berat_gram'     => $beratGram,
                'provinsi_toko'  => $namaProvinsiToko,
                'provinsi_user'  => $namaProvinsiUser,
                'beda_provinsi'  => $kategoriProvinsi === 'Beda Provinsi',
            ],
        ];
    }

    // ===================================================
    // HITUNG BERDASARKAN PROVINSI (koordinat tidak ada)
    // Total = biaya_provinsi + biaya_berat
    // ===================================================
    public static function hitungBerdasarkanProvinsi(
        string $namaProvinsiToko,
        string $namaProvinsiUser,
        float  $beratGram = 0
    ): array {
        $provinsiData     = self::hitungBiayaProvinsi($namaProvinsiToko, $namaProvinsiUser);
        $biayaProvinsi    = $provinsiData['tarif'];
        $kategoriProvinsi = $provinsiData['kategori'];
        $biayaBerat       = self::hitungBiayaBerat($beratGram);
        $totalOngkir      = $biayaProvinsi + $biayaBerat;

        $detail = [];
        $detail[] = sprintf(
            'Provinsi (%s, tanpa koordinat): Rp %s',
            $kategoriProvinsi,
            number_format($biayaProvinsi, 0, ',', '.')
        );
        $detail[] = sprintf(
            'Berat: %s gram (%s) = Rp %s',
            number_format($beratGram, 0, ',', '.'),
            $beratGram < 500 ? '< 500 gram' : '>= 500 gram',
            number_format($biayaBerat, 0, ',', '.')
        );

        $detailText = implode(' + ', $detail)
            . sprintf(' = Rp %s', number_format($totalOngkir, 0, ',', '.'));

        return [
            'ongkir'            => $totalOngkir,
            'biaya_provinsi'    => $biayaProvinsi,
            'biaya_berat'       => $biayaBerat,
            'kategori'          => $kategoriProvinsi . ' (tanpa koordinat)',
            'kategori_provinsi' => $kategoriProvinsi,
            'detail'            => $detailText,
            'menggunakan_jarak' => false,
            'rincian' => [
                'berat_gram'    => $beratGram,
                'provinsi_toko' => $namaProvinsiToko,
                'provinsi_user' => $namaProvinsiUser,
                'beda_provinsi' => $kategoriProvinsi === 'Beda Provinsi',
            ],
        ];
    }

    // ===================================================
    // MAIN — otomatis pilih metode
    // ===================================================
    public static function hitung(
        $tokoLat,
        $tokoLng,
        $userLat,
        $userLng,
        string $namaProvinsiToko,
        string $namaProvinsiUser,
        float  $beratGram = 0
    ): array {
        $tokoValid = self::koordinatValid($tokoLat, $tokoLng);
        $userValid = self::koordinatValid($userLat, $userLng);

        Log::info('OngkirHelper::hitung', [
            'toko'  => ['lat' => $tokoLat, 'lng' => $tokoLng, 'valid' => $tokoValid, 'provinsi' => $namaProvinsiToko],
            'user'  => ['lat' => $userLat, 'lng' => $userLng, 'valid' => $userValid, 'provinsi' => $namaProvinsiUser],
            'berat' => $beratGram,
        ]);

        if ($tokoValid && $userValid) {
            return self::hitungBerdasarkanJarak(
                (float) $tokoLat, (float) $tokoLng,
                (float) $userLat, (float) $userLng,
                $namaProvinsiToko, $namaProvinsiUser,
                $beratGram
            );
        }

        Log::warning('OngkirHelper: koordinat tidak lengkap, fallback ke provinsi', [
            'toko_valid' => $tokoValid,
            'user_valid' => $userValid,
        ]);

        return self::hitungBerdasarkanProvinsi($namaProvinsiToko, $namaProvinsiUser, $beratGram);
    }

    // ===================================================
    // FORMAT ONGKIR
    // ===================================================
    public static function formatOngkir(int $ongkir): string
    {
        return $ongkir > 0 ? 'Rp ' . number_format($ongkir, 0, ',', '.') : 'Gratis';
    }
}