package com.walkguide.service;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Map;

import static org.assertj.core.api.Assertions.*;

/**
 * Unit test untuk FcmService.
 *
 * FcmService saat ini berjalan dalam mode LOG-ONLY (tidak mengirim FCM nyata),
 * sehingga test di sini memastikan:
 *  1. Metode tidak melempar exception dalam kondisi normal
 *  2. Metode gracefully handle token kosong / null
 *  3. sendHighPriority mendelegasikan ke sendToToken tanpa error
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("FcmService Unit Tests")
class FcmServiceTest {

    @InjectMocks
    FcmService fcmService;

    private static final String VALID_TOKEN = "fcm-token-abc123xyz";
    private static final String TITLE = "Test Title";
    private static final String BODY = "Test Body";
    private static final Map<String, String> DATA = Map.of("type", "TEST");

    // ===== sendToToken TESTS =====

    @Test
    @DisplayName("sendToToken - token valid harus tidak throw exception")
    void sendToToken_validToken_shouldNotThrow() {
        assertThatNoException().isThrownBy(() ->
                fcmService.sendToToken(VALID_TOKEN, TITLE, BODY, DATA));
    }

    @Test
    @DisplayName("sendToToken - token null harus tidak throw exception (skip gracefully)")
    void sendToToken_nullToken_shouldNotThrow() {
        assertThatNoException().isThrownBy(() ->
                fcmService.sendToToken(null, TITLE, BODY, DATA));
    }

    @Test
    @DisplayName("sendToToken - token kosong/blank harus tidak throw exception")
    void sendToToken_blankToken_shouldNotThrow() {
        assertThatNoException().isThrownBy(() ->
                fcmService.sendToToken("", TITLE, BODY, DATA));

        assertThatNoException().isThrownBy(() ->
                fcmService.sendToToken("   ", TITLE, BODY, DATA));
    }

    @Test
    @DisplayName("sendToToken - data null harus tidak throw exception")
    void sendToToken_nullData_shouldNotThrow() {
        assertThatNoException().isThrownBy(() ->
                fcmService.sendToToken(VALID_TOKEN, TITLE, BODY, null));
    }

    @Test
    @DisplayName("sendToToken - data kosong (empty map) harus tidak throw exception")
    void sendToToken_emptyData_shouldNotThrow() {
        assertThatNoException().isThrownBy(() ->
                fcmService.sendToToken(VALID_TOKEN, TITLE, BODY, Map.of()));
    }

    @Test
    @DisplayName("sendToToken - title null harus tidak throw exception")
    void sendToToken_nullTitle_shouldNotThrow() {
        assertThatNoException().isThrownBy(() ->
                fcmService.sendToToken(VALID_TOKEN, null, BODY, DATA));
    }

    @Test
    @DisplayName("sendToToken - body null harus tidak throw exception")
    void sendToToken_nullBody_shouldNotThrow() {
        assertThatNoException().isThrownBy(() ->
                fcmService.sendToToken(VALID_TOKEN, TITLE, null, DATA));
    }

    // ===== sendHighPriority TESTS =====

    @Test
    @DisplayName("sendHighPriority - token valid harus tidak throw exception")
    void sendHighPriority_validToken_shouldNotThrow() {
        assertThatNoException().isThrownBy(() ->
                fcmService.sendHighPriority(VALID_TOKEN, TITLE, BODY, DATA));
    }

    @Test
    @DisplayName("sendHighPriority - token null harus tidak throw exception")
    void sendHighPriority_nullToken_shouldNotThrow() {
        assertThatNoException().isThrownBy(() ->
                fcmService.sendHighPriority(null, TITLE, BODY, DATA));
    }

    @Test
    @DisplayName("sendHighPriority - token kosong harus tidak throw exception")
    void sendHighPriority_blankToken_shouldNotThrow() {
        assertThatNoException().isThrownBy(() ->
                fcmService.sendHighPriority("", TITLE, BODY, null));
    }

    @Test
    @DisplayName("sendHighPriority - data SOS payload besar harus ditangani tanpa error")
    void sendHighPriority_sosBigPayload_shouldNotThrow() {
        Map<String, String> sosData = Map.of(
                "type", "SOS_TRIGGERED",
                "sosId", "12345",
                "userId", "99",
                "lat", "-7.257472",
                "lng", "112.752088",
                "address", "Jl. Kenangan No. 1, Surabaya"
        );

        assertThatNoException().isThrownBy(() ->
                fcmService.sendHighPriority(VALID_TOKEN, "SOS Darurat!", "Pengguna membutuhkan bantuan", sosData));
    }
}