# (c) cavaliba.com - test_datatask_celery

import uuid
from unittest.mock import patch

from django.test import TestCase
from django.utils import timezone

from app_data.models import DataTask
from app_data.task_manager import create_datatask, is_aborted, abort_task
from app_data.tasks import submit_example_long, task_example_long


class TestTaskExampleLong(TestCase):

    def test_queued_to_done(self):
        dt = create_datatask("example", params={"steps": 3}, owner_id="u1",
                             singleton=None)
        task_example_long(str(dt.handle), {"steps": 3})
        dt.refresh_from_db()
        self.assertEqual(dt.state, "DONE")
        self.assertIsNotNone(dt.finished_at)
        self.assertEqual(dt.output["steps_done"], 3)


    def test_progress_updated(self):
        dt = create_datatask("example", params={"steps": 4}, owner_id="u1")
        task_example_long(str(dt.handle), {"steps": 4})
        dt.refresh_from_db()
        self.assertIsNotNone(dt.progress)
        self.assertEqual(dt.progress["percent"], 100)
        self.assertEqual(dt.progress["total"], 4)


    def test_abort_mid_task(self):
        dt = create_datatask("example", owner_id="u1")
        # Set ABORTED before task checks — task should exit without DONE
        abort_task(dt.handle)
        task_example_long(str(dt.handle), {"steps": 10})
        dt.refresh_from_db()
        # Task was already ABORTED; state must not flip to DONE
        self.assertNotEqual(dt.state, "DONE")


    def test_failed_on_bad_params(self):
        dt = create_datatask("example", owner_id="u1")
        # Pass params that will cause an exception inside the task
        # (steps as string causes int() arithmetic to fail in range())
        task_example_long(str(dt.handle), {"steps": "not_an_int"})
        dt.refresh_from_db()
        self.assertEqual(dt.state, "FAILED")
        self.assertIsNotNone(dt.output)
        self.assertIn("error", dt.output)


    def test_unknown_handle_is_noop(self):
        import uuid
        # Should not raise — task silently returns if DataTask not found
        task_example_long(str(uuid.uuid4()), {})


    def test_submit_returns_handle(self):
        with patch("app_data.tasks.task_example_long.delay"):
            handle = submit_example_long(params={"steps": 2}, owner_type="auto", owner_id="system")
        self.assertIsNotNone(handle)
        dt = DataTask.objects.get(handle=handle)
        self.assertEqual(dt.state, "QUEUED")


    def test_submit_singleton_blocked(self):
        with patch("app_data.tasks.task_example_long.delay"):
            h1 = submit_example_long(owner_id="system")
            h2 = submit_example_long(owner_id="system")
        self.assertIsNotNone(h1)
        self.assertIsNone(h2)
