import logging
from collections.abc import Mapping, Sequence

from kele.config import ExecutorConfig, RunControlConfig
from kele.control import InferencePath, InferenceStatus, create_executor_manager
from kele.control.status import MainLoopManager, QuerySolutionManager
from kele.equality import Equivalence
from kele.grounder import GroundedRule
from kele.knowledge_bases import FactBase
from kele.syntax import FACT_TYPE, CompoundTerm, Constant, Question, SankuManagementSystem, Variable, _QuestionRule
from kele._utils import summarize_items

logger = logging.getLogger(__name__)


class Executor:
    """Check grounded rules and update the fact base."""
    def __init__(self,  # noqa: PLR0913
                 equivalence: Equivalence,
                 sk_system_handler: SankuManagementSystem,
                 fact_base: FactBase,
                 *,
                 main_loop_manager: MainLoopManager | None = None,  # 仅用于更新主循环控制器。如在测试executor功能时可以为空
                 solution_manager: QuerySolutionManager,
                 inference_path: InferencePath | None = None,  # 如在测试executor功能时可以为空
                 args: ExecutorConfig,
                 ):
        """Create an executor for grounded rule checking.

        :param equivalence: Equivalence manager.
        :param sk_system_handler: Handler for the three systems (text base,
            database, knowledge base). This is currently a placeholder.
        :param fact_base: Fact base to update with derived facts.
        :param main_loop_manager: Main loop controller (optional for tests).
        :param solution_manager: Solution manager for query bindings.
        :param inference_path: Inference path recorder (optional for tests).
        :param args: Executor configuration for rule selection and termination.
        """
        self.grounded_rules: Sequence[GroundedRule]
        self.args = args
        # TODO: 此时的select num是从abstract rule层面进行选择的，但理想情况下能否进一步，对每个abstract rule选择其候选值。
        #  不过也要考虑到的是，这里的选择和grounder结束时的选择是接近重复的
        self.equivalence = equivalence
        self.sk_system_handler = sk_system_handler

        self.fact_base = fact_base  # 仅用于更新全局事实，不用于推理

        self.executor_manager = create_executor_manager(
            equivalence, sk_system_handler,
            solution_manager=solution_manager,
            args=self.args
        )

        self.main_loop_manager = main_loop_manager

        self.inference_path = inference_path if inference_path is not None else InferencePath(args=RunControlConfig(), equivalence=self.equivalence)
        # FIXME: 只是为了本次PR改动不要太大的妥协，正常是executor要传一个args参的。另外这个参数None仅用于测试需求

    def get_equivalence(self) -> Equivalence:
        """Return the equivalence manager."""
        return self.equivalence

    def _sort_grounded_rules(self, question: Question) -> None:
        """
        Sort grounded rules so higher-priority rules execute first.
        """
        self.grounded_rules = self.grounded_rules   # TODO: 这里是要优化为更优策略的

    def execute(self, grounded_rules: Sequence[GroundedRule], question: Question) -> InferenceStatus:
        """
        Execute the check phase for grounded rules and update facts.

        The main-loop status is updated after each rule. Execution stops when
        terminal conditions are met.
        """
        logger.info("Starting execution for %s", question.description)

        self.grounded_rules = grounded_rules
        self._sort_grounded_rules(question)

        try:
            select_num = len(self.grounded_rules) if self.args.executing_rule_num == -1 else self.args.executing_rule_num
            for i in range(min(select_num, len(self.grounded_rules))):
                grounding_result = grounded_rules[i].check_grounding()

                logger.info(
                    "Generate %s%i%s grounded rules from %s%s%s",
                    "\033[91m", len(grounding_result), "\033[0m",  # \033[91m红色，\033[0m黑色
                    "\033[96m", grounded_rules[i].rule, "\033[0m"  # \033[96m青绿色
                )

                if logger.isEnabledFor(logging.DEBUG):
                    grounded_rule_text = grounded_rules[i].print_all_grounded_rules()
                    summary = summarize_items(grounded_rule_text)
                    logger.debug(
                        "all grounded rule text summary (unique rows: %s): %s",
                        grounded_rules[i].total_table_unique_height(),
                        summary,
                    )

                added_facts = self._update_facts(grounding_result)
                logger.info(
                    "%s%i%s new facts are derived from Rule %s%s%s",
                    "\033[91m", len(added_facts), "\033[0m",  # \033[91m红色，\033[0m黑色
                    "\033[96m", grounded_rules[i].rule, "\033[0m"  # \033[96m青绿色
                )

                if logger.isEnabledFor(logging.DEBUG):
                    summary = summarize_items(added_facts, formatter=str)
                    logger.debug("new facts summary: %s", summary)

                if self.main_loop_manager and not isinstance(grounded_rules[i].rule, _QuestionRule):
                    self.main_loop_manager.update_normal_rule_activation(new_facts=added_facts, used_rule=grounded_rules[i].rule)

                solutions: list[Mapping[Variable, Constant | CompoundTerm]] = []
                question_rule: _QuestionRule | None = None

                if isinstance(grounded_rules[i].rule, _QuestionRule):
                    solutions, question_rule = grounded_rules[i].get_question_solutions()

                # 检查执行器状态
                status = self.executor_manager.check_status(
                    new_facts=added_facts,
                    question=question,
                    solutions=solutions,
                    question_rule=question_rule
                )
                logger.info("Step %d status: %s", self.executor_manager.step_num, status.log_message())
                if not isinstance(grounded_rules[i].rule, _QuestionRule):
                    self.executor_manager.next_step()

                if status.is_terminal_for_executor():
                    return status

        except SystemExit:
            logger.exception("Execution interrupted by SystemExit")
            return InferenceStatus.EXTERNALLY_INTERRUPTED

        return InferenceStatus.NO_MORE_RULES

    def _update_facts(self, new_facts: list[FACT_TYPE]) -> list[FACT_TYPE]:
        """
        Update the fact base with newly derived facts.

        :param new_facts: Instantiated facts from this round.
        :returns: Facts that were added.
        """
        added_facts = self.fact_base.add_facts(facts=new_facts)  # 更新事实库后就不需要单独更新等价类了
        self.sk_system_handler.update_facts(new_facts)

        return added_facts

    def reset(self) -> None:
        """Reset internal state for a new question."""
        self.executor_manager.reset_for_new_inference()
