"""Performancetest-runner tests collector."""

from typing import ClassVar, cast

from bs4 import Tag

from collector_utilities.functions import match_string_or_regular_expression
from collector_utilities.type import Response
from model import SourceMeasurement, SourceResponses

from .base import PerformanceTestRunnerBaseClass


class PerformanceTestRunnerTests(PerformanceTestRunnerBaseClass):
    """Collector for the number of (successful and/or failing) performance test transactions."""

    # For each tests status, the column in the HMTL table that contains the number of tests with that status:
    COLUMN_INDICES: ClassVar[dict[str, int]] = {"failed": 7, "success": 1}

    async def _parse_source_responses(self, responses: SourceResponses) -> SourceMeasurement:
        """Override to parse the transactions from the responses and return the transactions with the desired status."""
        transactions_to_include = cast(list[str], self._parameter("transactions_to_include"))
        transactions_to_ignore = cast(list[str], self._parameter("transactions_to_ignore"))
        counts = {"failed": 0, "success": 0}
        for response in responses:
            count = await self.__parse_response(response, transactions_to_include, transactions_to_ignore)
            for status in count:
                counts[status] += count[status]
        value = sum(counts[status] for status in self._parameter("test_result"))
        return SourceMeasurement(value=str(value), total=str(sum(counts.values())))

    @classmethod
    async def __parse_response(
        cls,
        response: Response,
        transactions_to_include: list[str],
        transactions_to_ignore: list[str],
    ) -> dict[str, int]:
        """Parse the transactions from the response."""
        soup = await cls._soup(response)
        count = {"failed": 0, "success": 0}
        for transaction in cast(Tag, soup.find(id="responsetimestable_begin")).select("tr.transaction"):
            name = cls._name(transaction)
            if transactions_to_include and not match_string_or_regular_expression(name, transactions_to_include):
                continue
            if match_string_or_regular_expression(name, transactions_to_ignore):
                continue
            columns = transaction.find_all("td")
            for status, column_index in cls.COLUMN_INDICES.items():
                nr_tests = int(columns[column_index].string or 0)
                count[status] += nr_tests
        return count
