import re
from typing import List

from pyutils import exc

from evowluator.data.ontology import Syntax
from evowluator.reasoner.base import (
    MetaArgs,
    Reasoner,
    ReasoningTask
)
from evowluator.reasoner.results import (
    ReasoningResults,
    ResultsParser,
    StandardReasoningResults,
    EvaluationTask
)
from evowluator.evaluation.mode import EvaluationMode


class KoncludeResultsParser(ResultsParser):
    """Parser for Konclude results."""

    def parse_classification_results(self, task: EvaluationTask) -> ReasoningResults:
        stats = self._parse_reasoning_stats(task)

        res = re.search(r'Query \'UnnamedWriteClassHierarchyQuery\' processed in \'(.*)\' ms\.',
                        task.stdout)

        if res:
            write_ms = float(res.group(1))
            stats = StandardReasoningResults(output='', output_is_file=False,
                                             parsing_ms=stats.parsing_ms,
                                             reasoning_ms=stats.reasoning_ms - write_ms,
                                             max_memory=stats.max_memory,
                                             energy_stats=stats.energy_stats)

        return stats

    def parse_consistency_results(self, task: EvaluationTask) -> ReasoningResults:
        results = self._parse_reasoning_stats(task)

        res = re.search(r'Ontology \'.*\' is (.*)\.', task.stdout)
        exc.raise_if_falsy(res=res)
        output = 'consistent' if res.group(1) == 'consistent' else 'inconsistent'

        return results.with_output(output, is_file=False)

    def _parse_reasoning_stats(self, task: EvaluationTask) -> StandardReasoningResults:
        stdout = task.stdout
        exc.raise_if_falsy(stdout=stdout)

        res = re.search(r'>> Ontology parsed in (.*) ms\.', stdout)
        parsing_ms = float(res.group(1)) if res else 0.0

        res = re.search(r'Total processing time: (.*) ms\.', stdout)
        total_ms = float(res.group(1)) if res else 0.0

        if parsing_ms <= 0.0:
            parsing_ms = 1.0

        reasoning_ms = total_ms - parsing_ms

        if reasoning_ms <= 0.0:
            reasoning_ms = 1.0

        return StandardReasoningResults(output='', output_is_file=False,
                                        parsing_ms=parsing_ms,
                                        reasoning_ms=reasoning_ms,
                                        max_memory=self._parse_memory(task),
                                        energy_stats=self._parse_energy(task))


class Konclude(Reasoner):
    """Konclude reasoner wrapper."""

    @property
    def name(self) -> str:
        return 'Konclude'

    @property
    def path(self) -> str:
        return 'Konclude/Binaries/Konclude'

    @property
    def supported_syntaxes(self) -> List[Syntax]:
        return [Syntax.FUNCTIONAL]

    @property
    def results_parser(self) -> ResultsParser:
        return KoncludeResultsParser()

    def args(self, task: ReasoningTask, mode: EvaluationMode) -> List[str]:
        if task == ReasoningTask.CLASSIFICATION:
            args = ['classification', '-i', MetaArgs.INPUT]
            if mode == EvaluationMode.CORRECTNESS:
                args.extend(['-o', MetaArgs.OUTPUT])
            args.append('-v')
        elif task == ReasoningTask.CONSISTENCY:
            args = ['consistency', '-i', MetaArgs.INPUT, '-v']
        else:
            args = []

        return args
