# Copyright (c) 2026 Roman Shaban. All rights reserved.

# Licensed under the Apache License 2.0.

# Part of the CIOS / Onto-Protocol Ecosystem.

import json

import os

from typing import Dict, List, Optional


from onto_models import OntoTask

from persistence import save_task

from recovery import load_task_by_id



STORAGE_DIR = "storage"

TASKS_FILE = os.path.join(STORAGE_DIR, "tasks.json")



def _load_tasks() -> Dict[str, dict]:

    if not os.path.exists(TASKS_FILE):

        raise FileNotFoundError("tasks.json not found. Run the system first.")

    with open(TASKS_FILE, "r", encoding="utf-8") as f:

        return json.load(f)



def get_children_of_parent(parent_task_id: str) -> List[dict]:

    tasks = _load_tasks()

    children = [

        task for task in tasks.values()

        if task.get("parent_task_id") == parent_task_id

    ]

    children.sort(key=lambda t: t.get("timestamp", ""))

    return children



def reconcile_parent(parent_task_id: str) -> Optional[OntoTask]:

    parent_task = load_task_by_id(parent_task_id)

    if parent_task is None:

        print(f"Parent task not found: {parent_task_id}")

        return None


    children = get_children_of_parent(parent_task_id)


    print("=== RECONCILIATION REQUEST ===")

    print(f"Parent task ID: {parent_task.task_id}")

    print(f"Parent current status: {parent_task.result.status}")

    print(f"Found children: {len(children)}")


    if not children:

        print("No child tasks found. Nothing to reconcile.")

        return parent_task


    child_statuses = [child.get("status") for child in children]

    print("Child statuses:", child_statuses)


    # Rule 1: if any child is blocked -> parent stays failed

    if any(status == "blocked" for status in child_statuses):

        parent_task.result.status = "failed"

        parent_task.result.output = "Reconciliation: parent remains failed because at least one child is blocked"

        save_task(parent_task)


        print("Reconciliation result: parent remains failed (blocked child exists)")

        return parent_task


    # Rule 2: if any child is failed -> parent stays failed

    if any(status == "failed" for status in child_statuses):

        parent_task.result.status = "failed"

        parent_task.result.output = "Reconciliation: parent remains failed because at least one child failed"

        save_task(parent_task)


        print("Reconciliation result: parent remains failed (failed child exists)")

        return parent_task


    # Rule 3: if all children completed -> parent becomes completed

    if all(status == "completed" for status in child_statuses):

        parent_task.result.status = "completed"

        parent_task.result.output = "Reconciled: all child tasks completed successfully"

        save_task(parent_task)


        print("Reconciliation result: parent updated to completed")

        return parent_task


    # Rule 4: otherwise leave unchanged

    print("Reconciliation result: no change")

    return parent_task



def reconcile_from_child(child_task_id: str) -> Optional[OntoTask]:

    child_task = load_task_by_id(child_task_id)

    if child_task is None:

        print(f"Child task not found: {child_task_id}")

        return None


    parent_task_id = child_task.parent_task_id

    if not parent_task_id:

        print("This task has no parent. Nothing to reconcile.")

        return child_task


    return reconcile_parent(parent_task_id)