package kz.konturai.parser.service;

import kz.konturai.parser.model.MarketItem;
import kz.konturai.parser.repository.MarketItemRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.TestPropertySource;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@EnabledIfEnvironmentVariable(named = "RUN_INTEGRATION_TESTS", matches = "true")
@TestPropertySource(properties = {
        "spring.data.mongodb.host=${MONGODB_HOST:localhost}",
        "spring.data.mongodb.port=${MONGODB_PORT:27017}",
        "spring.data.mongodb.database=parser_test_db",
        "spring.data.mongodb.username=${MONGODB_USERNAME:}",
        "spring.data.mongodb.password=${MONGODB_PASSWORD:}",
        "spring.data.mongodb.authentication-database=${MONGODB_AUTH_DATABASE:admin}"
})
public class MarketItemServiceTest {

    @Autowired
    private MarketItemService marketItemService;

    @Autowired
    private MarketItemRepository marketItemRepository;

    @BeforeEach
    public void setUp() {
        // Очищаем базу данных перед каждым тестом
        marketItemRepository.deleteAll();

        // Создаем тестовые данные
        createTestData();
    }

    private void createTestData() {
        // Создаем записи для Kursiv
        MarketItem kursivItem1 = new MarketItem();
        kursivItem1.setSourceName("Kursiv (Бизнес/экономика)");
        kursivItem1.setTitle("Test Kursiv News 1");
        kursivItem1.setUrl("https://kursiv.media/test1");
        kursivItem1.setPublishedAt(LocalDateTime.now().minusDays(1));
        kursivItem1.setHash("kursiv_hash_1");
        marketItemRepository.save(kursivItem1);

        MarketItem kursivItem2 = new MarketItem();
        kursivItem2.setSourceName("Kursiv (Бизнес/экономика)");
        kursivItem2.setTitle("Test Kursiv News 2");
        kursivItem2.setUrl("https://kursiv.media/test2");
        kursivItem2.setPublishedAt(LocalDateTime.now().minusDays(2));
        kursivItem2.setHash("kursiv_hash_2");
        marketItemRepository.save(kursivItem2);

        // Создаем записи для Kapital
        MarketItem kapitalItem1 = new MarketItem();
        kapitalItem1.setSourceName("Kapital.kz (Бизнес)");
        kapitalItem1.setTitle("Test Kapital News 1");
        kapitalItem1.setUrl("https://kapital.kz/test1");
        kapitalItem1.setPublishedAt(LocalDateTime.now().minusDays(3));
        kapitalItem1.setHash("kapital_hash_1");
        marketItemRepository.save(kapitalItem1);

        MarketItem kapitalItem2 = new MarketItem();
        kapitalItem2.setSourceName("Kapital.kz (Бизнес)");
        kapitalItem2.setTitle("Test Kapital News 2");
        kapitalItem2.setUrl("https://kapital.kz/test2");
        kapitalItem2.setPublishedAt(LocalDateTime.now().minusDays(4));
        kapitalItem2.setHash("kapital_hash_2");
        marketItemRepository.save(kapitalItem2);
    }

    @Test
    public void testGetAllItemsWithPagination() {
        Pageable pageable = PageRequest.of(0, 2, Sort.by("publishedAt").descending());
        Page<MarketItem> page = marketItemService.getAllItems(pageable);

        assertNotNull(page);
        assertEquals(4, page.getTotalElements());
        assertEquals(2, page.getContent().size());
        assertEquals(2, page.getTotalPages());
    }

    @Test
    public void testGetItemsBySource() {
        Pageable pageable = PageRequest.of(0, 10);
        Page<MarketItem> kursivItems = marketItemService.getItemsBySource("Kursiv (Бизнес/экономика)", pageable);

        assertNotNull(kursivItems);
        assertEquals(2, kursivItems.getTotalElements());
        assertEquals(2, kursivItems.getContent().size());

        // Проверяем, что все записи принадлежат Kursiv
        for (MarketItem item : kursivItems.getContent()) {
            assertEquals("Kursiv (Бизнес/экономика)", item.getSourceName());
        }
    }

    @Test
    public void testGetItemsByDateRange() {
        LocalDateTime startDate = LocalDateTime.now().minusDays(3);
        LocalDateTime endDate = LocalDateTime.now().minusDays(1);

        Pageable pageable = PageRequest.of(0, 10);
        Page<MarketItem> items = marketItemService.getItemsByDateRange(startDate, endDate, pageable);

        assertNotNull(items);
        assertEquals(2, items.getTotalElements());

        // Проверяем, что все записи в указанном диапазоне дат
        for (MarketItem item : items.getContent()) {
            assertTrue(item.getPublishedAt().isAfter(startDate.minusSeconds(1)));
            assertTrue(item.getPublishedAt().isBefore(endDate.plusSeconds(1)));
        }
    }

    @Test
    public void testGetItemsWithFilters() {
        LocalDateTime startDate = LocalDateTime.now().minusDays(3);
        LocalDateTime endDate = LocalDateTime.now().minusDays(1);

        Pageable pageable = PageRequest.of(0, 10);
        Page<MarketItem> items = marketItemService.getItemsWithFilters(
                "Kursiv (Бизнес/экономика)", startDate, endDate, pageable);

        assertNotNull(items);
        assertEquals(1, items.getTotalElements());

        // Проверяем, что запись соответствует фильтрам
        MarketItem item = items.getContent().get(0);
        assertEquals("Kursiv (Бизнес/экономика)", item.getSourceName());
        assertTrue(item.getPublishedAt().isAfter(startDate.minusSeconds(1)));
        assertTrue(item.getPublishedAt().isBefore(endDate.plusSeconds(1)));
    }

    @Test
    public void testGetTotalItemsCount() {
        long count = marketItemService.getTotalItemsCount();
        assertEquals(4, count);
    }

    @Test
    public void testGetItemsCountBySource() {
        long kursivCount = marketItemService.getItemsCountBySource("Kursiv (Бизнес/экономика)");
        assertEquals(2, kursivCount);

        long kapitalCount = marketItemService.getItemsCountBySource("Kapital.kz (Бизнес)");
        assertEquals(2, kapitalCount);
    }

    @Test
    public void testGetAllSourceNames() {
        List<String> sources = marketItemService.getAllSourceNames();

        assertNotNull(sources);
        assertEquals(2, sources.size());
        assertTrue(sources.contains("Kursiv (Бизнес/экономика)"));
        assertTrue(sources.contains("Kapital.kz (Бизнес)"));
    }

    @Test
    public void testGetSourceStatistics() {
        Map<String, Long> statistics = marketItemService.getSourceStatistics();

        assertNotNull(statistics);
        assertEquals(2, statistics.size());
        assertEquals(Long.valueOf(2), statistics.get("Kursiv (Бизнес/экономика)"));
        assertEquals(Long.valueOf(2), statistics.get("Kapital.kz (Бизнес)"));
    }

    @Test
    public void testParseDate() {
        // Тест различных форматов даты
        LocalDateTime date1 = marketItemService.parseDate("2025-01-14");
        assertNotNull(date1);

        LocalDateTime date2 = marketItemService.parseDate("2025-01-14T10:30:00");
        assertNotNull(date2);

        LocalDateTime date3 = marketItemService.parseDate("2025-01-14T10:30:00.000");
        assertNotNull(date3);

        LocalDateTime date4 = marketItemService.parseDate("2025-01-14 10:30:00");
        assertNotNull(date4);

        // Тест null и пустой строки
        assertNull(marketItemService.parseDate(null));
        assertNull(marketItemService.parseDate(""));
        assertNull(marketItemService.parseDate("invalid-date"));
    }
}
