package kz.konturai.parser.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import kz.konturai.parser.config.FacebookLeadProperties;
import kz.konturai.parser.model.FacebookLead;
import kz.konturai.parser.repository.FacebookLeadRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class FacebookLeadCollectorServiceTest {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Mock
    private FacebookLeadGraphApiClient graphApiClient;

    @Mock
    private FacebookLeadRepository facebookLeadRepository;

    @Mock
    private FacebookLeadCallCenterSyncService callCenterSyncService;

    private FacebookLeadCollectorService service;

    @BeforeEach
    void setUp() {
        FacebookLeadProperties properties = new FacebookLeadProperties();
        properties.setPageId("page-1");
        properties.setAccessToken("token-1");

        service = new FacebookLeadCollectorService(
                properties,
                graphApiClient,
                facebookLeadRepository,
                callCenterSyncService
        );
    }

    @Test
    void collectHotLeadsShouldSaveOnlyNewMatchingComments() throws Exception {
        JsonNode firstPostsPage = objectMapper.readTree("""
                {
                  "data": [
                    {
                      "id": "post-1"
                    }
                  ]
                }
                """);

        JsonNode firstCommentsPage = objectMapper.readTree("""
                {
                  "data": [
                    {
                      "id": "comment-1",
                      "message": "Хочу купить, какая цена?",
                      "created_time": "2026-04-05T08:15:30+0000",
                      "from": {
                        "name": "Alice"
                      }
                    },
                    {
                      "id": "comment-2",
                      "message": "Спасибо за пост",
                      "created_time": "2026-04-05T08:16:30+0000",
                      "from": {
                        "name": "Bob"
                      }
                    },
                    {
                      "id": "comment-3",
                      "message": "НАПИШЕТЕ   В   ЛС",
                      "created_time": "2026-04-05T08:17:30+0000",
                      "from": {
                        "name": "Carol"
                      }
                    }
                  ]
                }
                """);

        when(graphApiClient.fetchPostsPage(null)).thenReturn(firstPostsPage);
        when(graphApiClient.fetchCommentsPage("post-1", null)).thenReturn(firstCommentsPage);
        when(facebookLeadRepository.existsByExternalCommentId("comment-1")).thenReturn(false);
        when(facebookLeadRepository.existsByExternalCommentId("comment-3")).thenReturn(true);
        when(facebookLeadRepository.save(any(FacebookLead.class))).thenAnswer(invocation -> invocation.getArgument(0));

        int savedCount = service.collectHotLeads();

        ArgumentCaptor<FacebookLead> leadCaptor = ArgumentCaptor.forClass(FacebookLead.class);
        verify(facebookLeadRepository).save(leadCaptor.capture());

        FacebookLead savedLead = leadCaptor.getValue();
        assertEquals(1, savedCount);
        assertEquals("comment-1", savedLead.getExternalCommentId());
        assertEquals("Alice", savedLead.getAuthorName());
        assertEquals("Хочу купить, какая цена?", savedLead.getMessage());
        assertEquals("NEW", savedLead.getStatus());
        assertEquals(2026, savedLead.getTimestamp().getYear());
        assertEquals(4, savedLead.getTimestamp().getMonthValue());
        assertEquals(5, savedLead.getTimestamp().getDayOfMonth());
        verify(facebookLeadRepository, never()).existsByExternalCommentId("comment-2");
        verify(callCenterSyncService).syncLead(any(FacebookLead.class));
    }

    @Test
    void collectHotLeadsShouldProcessNextPostsAndCommentsPages() throws Exception {
        JsonNode firstPostsPage = objectMapper.readTree("""
                {
                  "data": [
                    {
                      "id": "post-1"
                    }
                  ],
                  "paging": {
                    "cursors": {
                      "after": "posts-cursor-1"
                    }
                  }
                }
                """);

        JsonNode firstCommentsPage = objectMapper.readTree("""
                {
                  "data": [
                    {
                      "id": "comment-1",
                      "message": "Сколько стоит?",
                      "created_time": "2026-04-05T08:15:30+0000",
                      "from": {
                        "name": "Alice"
                      }
                    }
                  ],
                  "paging": {
                    "cursors": {
                      "after": "comments-cursor-1"
                    }
                  }
                }
                """);

        JsonNode secondCommentsPage = objectMapper.readTree("""
                {
                  "data": [
                    {
                      "id": "comment-2",
                      "message": "Как заказать?",
                      "created_time": "2026-04-05T08:16:30+0000",
                      "from": {
                        "name": "Bob"
                      }
                    }
                  ]
                }
                """);

        JsonNode secondPostsPage = objectMapper.readTree("""
                {
                  "data": [
                    {
                      "id": "post-2"
                    }
                  ]
                }
                """);

        JsonNode thirdCommentsPage = objectMapper.readTree("""
                {
                  "data": [
                    {
                      "id": "comment-3",
                      "message": "цена",
                      "created_time": "2026-04-05T08:17:30+0000",
                      "from": {
                        "name": "Carol"
                      }
                    }
                  ]
                }
                """);

        when(graphApiClient.fetchPostsPage(null)).thenReturn(firstPostsPage);
        when(graphApiClient.fetchCommentsPage("post-1", null)).thenReturn(firstCommentsPage);
        when(graphApiClient.fetchCommentsPage("post-1", "comments-cursor-1")).thenReturn(secondCommentsPage);
        when(graphApiClient.fetchPostsPage("posts-cursor-1")).thenReturn(secondPostsPage);
        when(graphApiClient.fetchCommentsPage("post-2", null)).thenReturn(thirdCommentsPage);
        when(facebookLeadRepository.existsByExternalCommentId(eq("comment-1"))).thenReturn(false);
        when(facebookLeadRepository.existsByExternalCommentId(eq("comment-2"))).thenReturn(false);
        when(facebookLeadRepository.existsByExternalCommentId(eq("comment-3"))).thenReturn(false);
        when(facebookLeadRepository.save(any(FacebookLead.class))).thenAnswer(invocation -> invocation.getArgument(0));

        int savedCount = service.collectHotLeads();

        assertEquals(3, savedCount);
        verify(graphApiClient).fetchPostsPage(null);
        verify(graphApiClient).fetchCommentsPage("post-1", null);
        verify(graphApiClient).fetchCommentsPage("post-1", "comments-cursor-1");
        verify(graphApiClient).fetchPostsPage("posts-cursor-1");
        verify(graphApiClient).fetchCommentsPage("post-2", null);
        verify(facebookLeadRepository, times(3)).save(any(FacebookLead.class));
        verify(callCenterSyncService, times(3)).syncLead(any(FacebookLead.class));
    }

    @Test
    void scheduledCollectionShouldSkipWhenCredentialsAreMissing() {
        FacebookLeadProperties properties = new FacebookLeadProperties();
        FacebookLeadCollectorService unconfiguredService =
                new FacebookLeadCollectorService(
                        properties,
                        graphApiClient,
                        facebookLeadRepository,
                        callCenterSyncService
                );

        unconfiguredService.collectHotLeadsScheduled();

        verifyNoInteractions(graphApiClient);
        verifyNoInteractions(facebookLeadRepository);
        verifyNoInteractions(callCenterSyncService);
    }

    @Test
    void startupCollectionShouldRunOnceWhenApplicationIsReady() throws Exception {
        JsonNode emptyPostsPage = objectMapper.readTree("""
                {
                  "data": []
                }
                """);

        when(graphApiClient.fetchPostsPage(null)).thenReturn(emptyPostsPage);

        service.collectHotLeadsOnStartup();

        verify(graphApiClient, times(1)).fetchPostsPage(null);
        verifyNoInteractions(facebookLeadRepository);
        verify(callCenterSyncService).syncPendingLeads();
    }

    @Test
    void normalizeForSearchShouldLowercaseCollapseWhitespaceAndReplaceYo() {
        String normalized = FacebookLeadCollectorService.normalizeForSearch("  Ёжик   НАПИШЕТЕ   В   ЛС  ");

        assertEquals("ежик напишете в лс", normalized);
        assertTrue(normalized.contains("напишете в лс"));
    }

    @Test
    void containsHotLeadKeywordShouldMatchExpandedKeywordRootsIgnoringCase() {
        assertTrue(FacebookLeadCollectorService.containsHotLeadKeyword("Подскажите, где находиться ваш филиал?"));
        assertTrue(FacebookLeadCollectorService.containsHotLeadKeyword("Есть ли ДОСТАВКА через Wolt?"));
        assertTrue(FacebookLeadCollectorService.containsHotLeadKeyword("Можно оплатить по Каспи QR или Red?"));
        assertTrue(FacebookLeadCollectorService.containsHotLeadKeyword("Напишите в личку номер телефона"));
        assertFalse(FacebookLeadCollectorService.containsHotLeadKeyword("Спасибо за красивый пост"));
    }
}
