#
#   Imandra Inc.
#
#   speclogician/logic/api/scenario.py
#

import asyncio
from .client import SpecLogicianImandraX
from speclogician.modeling.scenario import Scenario
from speclogician.modeling.spec import Spec


async def check_state_preds_async(sc: Scenario, spec: Spec) -> bool:
    if len(sc.given) == 0:
        return True
    
    async with SpecLogicianImandraX() as ix:
        res = await ix.check_scenario_consistent(
            domain_model=spec.domain_model,
            scenario=sc,
            check_state_preds=True,
            check_action_preds=False
        )

        return res.is_consistent

def check_state_preds(sc: Scenario, spec: Spec) -> bool:
    return asyncio.run(check_state_preds_async(sc, spec))


async def check_action_preds_async(sc: Scenario, spec: Spec) -> bool:
    if len(sc.when) == 0:
        return True

    async with SpecLogicianImandraX() as ix:
        res = await ix.check_scenario_consistent(
            domain_model=spec.domain_model,
            scenario=sc,
            check_state_preds=False,
            check_action_preds=True
        )
        return res.is_consistent

def check_action_preds (sc: Scenario, spec: Spec) -> bool:
    return asyncio.run(check_action_preds_async(sc, spec))

async def check_all_preds_async(sc : Scenario, spec : Spec) -> bool:
    if len(sc.given) == 0 and len(sc.when) == 0:
        return True
    
    async with SpecLogicianImandraX() as ix:
        res = await ix.check_scenario_consistent(
            domain_model=spec.domain_model,
            scenario=sc,
            check_state_preds=True,
            check_action_preds=True
        )
        return res.is_consistent

def check_all_preds (sc: Scenario, spec: Spec) -> bool:
    return asyncio.run(check_all_preds_async(sc, spec))

def check_scenario(sc : Scenario, spec : Spec) -> None:
    """
    Check if all the specified predicates/transitions are actually present in the domain model,
    and if so, check that the predicates are consistent
    """

    # First, let's check that all the predicates exist..
    sc.preds_missing = []
    for p in list(sc.given) + list(sc.when):
        if not spec.domain_model.pred_exists(p):
            sc.preds_missing.append(p)

    sc.trans_missing = []
    for t in sc.then:
        if not spec.domain_model.trans_exists(t):
            sc.trans_missing.append(t)

    sc.given_preds_consistent = check_state_preds(sc, spec)
    sc.when_preds_consistent = check_action_preds(sc, spec)
    sc.all_preds_consistent = check_all_preds(sc, spec)


async def check_intersection_async(sc1: Scenario, sc2: Scenario, spec: Spec) -> bool:
    """
    Async: return True iff scenarios intersect (SAT).
    """
    async with SpecLogicianImandraX() as ix:
        res = await ix.check_scenarios_intersect(
            domain_model=spec.domain_model,
            sc_a=sc1,
            sc_b=sc2,
        )
        return res.do_they_intersect

def check_intersection(sc1: Scenario, sc2: Scenario, spec: Spec) -> bool:
    """
    Sync wrapper around `check_intersection_async`.
    Returns True iff scenarios intersect (SAT).
    """
    return asyncio.run(check_intersection_async(sc1, sc2, spec))