from datetime import datetime

import pytest

from scrapy.extensions.logstats import LogStats
from scrapy.utils.test import get_crawler
from tests.spiders import SimpleSpider
from tests.utils.decorators import coroutine_test


class TestLogStats:
    def setup_method(self):
        self.crawler = get_crawler(SimpleSpider)
        self.spider = self.crawler._create_spider("spidey")
        self.stats = self.crawler.stats

        self.stats.set_value("response_received_count", 4802)
        self.stats.set_value("item_scraped_count", 3201)

    @coroutine_test
    async def test_stats_calculations(self):
        logstats = LogStats.from_crawler(self.crawler)

        with pytest.raises(AttributeError):
            logstats.pagesprev
        with pytest.raises(AttributeError):
            logstats.itemsprev

        logstats.spider_opened(self.spider)
        assert logstats.pagesprev == 4802
        assert logstats.itemsprev == 3201

        logstats.calculate_stats()
        assert logstats.items == 3201
        assert logstats.pages == 4802
        assert logstats.irate == 0.0
        assert logstats.prate == 0.0
        assert logstats.pagesprev == 4802
        assert logstats.itemsprev == 3201

        # Simulate what happens after a minute
        self.stats.set_value("response_received_count", 5187)
        self.stats.set_value("item_scraped_count", 3492)
        logstats.calculate_stats()
        assert logstats.items == 3492
        assert logstats.pages == 5187
        assert logstats.irate == 291.0
        assert logstats.prate == 385.0
        assert logstats.pagesprev == 5187
        assert logstats.itemsprev == 3492

        # Simulate when spider closes after running for 30 mins
        self.stats.set_value("start_time", datetime.fromtimestamp(1655100172))
        self.stats.set_value("finish_time", datetime.fromtimestamp(1655101972))
        logstats.spider_closed(self.spider, "test reason")
        assert self.stats.get_value("responses_per_minute") == 172.9
        assert self.stats.get_value("items_per_minute") == 116.4

    def test_stats_calculations_no_time(self):
        """The stat values should be None since the start and finish time are
        not available.
        """
        logstats = LogStats.from_crawler(self.crawler)
        logstats.spider_closed(self.spider, "test reason")
        assert self.stats.get_value("responses_per_minute") is None
        assert self.stats.get_value("items_per_minute") is None

    def test_stats_calculation_no_elapsed_time(self):
        """The stat values should be None since the elapsed time is 0."""
        logstats = LogStats.from_crawler(self.crawler)
        self.stats.set_value("start_time", datetime.fromtimestamp(1655100172))
        self.stats.set_value("finish_time", datetime.fromtimestamp(1655100172))
        logstats.spider_closed(self.spider, "test reason")
        assert self.stats.get_value("responses_per_minute") is None
        assert self.stats.get_value("items_per_minute") is None
