# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========

import asyncio

from mirage.io.types import IOResult
from mirage.resource.ram import RAMResource
from mirage.shell.job_table import JobStatus, JobTable
from mirage.types import DEFAULT_SESSION_ID, MountMode
from mirage.workspace import Workspace
from mirage.workspace.types import ExecutionNode


async def _make_failing_task():
    raise RuntimeError("resource API error")


async def _make_successful_task():
    return b"hello", IOResult(exit_code=0), ExecutionNode(command="echo hello",
                                                          exit_code=0)


def test_wait_handles_task_exception():

    async def _run():
        table = JobTable()
        task = asyncio.create_task(_make_failing_task())
        table.submit(command="bad_cmd", task=task, cwd="/")
        job = await table.wait(1)
        assert job.status == JobStatus.COMPLETED
        assert job.exit_code == 1
        assert b"resource API error" in job.stderr

    asyncio.run(_run())


def test_wait_all_survives_failing_task():

    async def _run():
        table = JobTable()
        task1 = asyncio.create_task(_make_failing_task())
        task2 = asyncio.create_task(_make_successful_task())
        table.submit(command="bad", task=task1, cwd="/")
        table.submit(command="good", task=task2, cwd="/")
        jobs = await table.wait_all()
        assert len(jobs) == 2
        bad = table.get(1)
        good = table.get(2)
        assert bad.exit_code == 1
        assert good.exit_code == 0
        assert good.stdout == b"hello"

    asyncio.run(_run())


def test_wait_successful_task():

    async def _run():
        table = JobTable()
        task = asyncio.create_task(_make_successful_task())
        table.submit(command="echo hello", task=task, cwd="/")
        job = await table.wait(1)
        assert job.status == JobStatus.COMPLETED
        assert job.exit_code == 0
        assert job.stdout == b"hello"

    asyncio.run(_run())


def test_background_does_not_consume_stdin():

    async def _run():
        mem = RAMResource()
        ws = Workspace(
            {"/data": (mem, MountMode.WRITE)},
            mode=MountMode.WRITE,
        )
        ws.get_session(DEFAULT_SESSION_ID).cwd = "/data"
        io = await ws.execute("sleep 0 & cat", stdin=b"hello\n")
        assert (await io.stdout_str()).strip() == "hello"

    asyncio.run(_run())
