            A short description of the task to be completed. "Sort the service catalog item list"
        """
        super().__init__(
            seed=seed,
            instance=instance,
            fixed_config=fixed_config,
            navigation_config={
                "application": "Service Catalog",
                "module": "Catalog Definitions > Maintain Items",
            },
            level=level,
            function=get_infeasible_sort_config,
            task_class=SortServiceCatalogItemListTask,
            provide_reason=True,
        )
        self.task_description = "Sort the service catalog item list based on specific criteria. \n"
        self.short_description = "Sort the service catalog item list."
        self.list_name = list_name

class InfeasibleNavigateAndSortServiceCatalogItemListTask(InfeasibleNavigateAndDoTask):
    def __init__(
        self,
        seed: int = None,
        instance: SNowInstance = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
        list_name: str = "service_catalog_item",
    ) -> None:
        """
        Infeasible version of navigate to the service catalog item list page and sort the list based on a specific criteria.

        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Sort the service catalog item list"
        """
        super().__init__(
            seed=seed,
            instance=instance,
            fixed_config=fixed_config,
            navigation_config={
                "application": "Service Catalog",
                "module": "Catalog Definitions > Maintain Items",
            },
            level=level,
            provide_reason=False,
            function=get_infeasible_sort_config,
            task_class=SortServiceCatalogItemListTask,
        )
        self.task_description = "Sort the service catalog item list based on specific criteria. \n"
        self.short_description = "Sort the service catalog item list."
        self.list_name = list_name

local_vars = locals().copy()

__TASKS__ = [
    var
    for var in local_vars.values()
    if isinstance(var, type)
    and issubclass(var, InfeasibleNavigateAndDoTask)
    and var is not InfeasibleNavigateAndDoTask
]

INFEASIBLE_NAVIGATE_AND_CREATE_WITH_REASON = [
    InfeasibleNavigateAndCreateUserWithReasonTask,
    InfeasibleNavigateAndCreateIncidentWithReasonTask,
    InfeasibleNavigateAndCreateChangeRequestWithReasonTask,
    InfeasibleNavigateAndCreateProblemWithReasonTask,
    InfeasibleNavigateAndCreateHardwareAssetWithReasonTask,
]
INFEASIBLE_NAVIGATE_AND_CREATE = [


        """
        super().__init__(
            seed=seed,
            instance=instance,
            fixed_config=fixed_config,
            navigation_config={
                "application": "Service Catalog",
                "module": "Catalog Definitions > Maintain Items",
            },
            level=level,
            function=get_infeasible_sort_config,
            task_class=SortServiceCatalogItemListTask,
            provide_reason=True,
        )
        self.task_description = "Sort the service catalog item list based on specific criteria. \n"
        self.short_description = "Sort the service catalog item list."
        self.list_name = list_name

class InfeasibleNavigateAndSortServiceCatalogItemListTask(InfeasibleNavigateAndDoTask):
    def __init__(
        self,
        seed: int = None,
        instance: SNowInstance = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
        list_name: str = "service_catalog_item",
    ) -> None:
        """
        Infeasible version of navigate to the service catalog item list page and sort the list based on a specific criteria.

        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Sort the service catalog item list"
        """
        super().__init__(
            seed=seed,
            instance=instance,
            fixed_config=fixed_config,
            navigation_config={
                "application": "Service Catalog",
                "module": "Catalog Definitions > Maintain Items",
            },
            level=level,
            provide_reason=False,
            function=get_infeasible_sort_config,
            task_class=SortServiceCatalogItemListTask,
        )
        self.task_description = "Sort the service catalog item list based on specific criteria. \n"
        self.short_description = "Sort the service catalog item list."
        self.list_name = list_name

local_vars = locals().copy()

__TASKS__ = [
    var
    for var in local_vars.values()
    if isinstance(var, type)
    and issubclass(var, InfeasibleNavigateAndDoTask)
    and var is not InfeasibleNavigateAndDoTask
]

INFEASIBLE_NAVIGATE_AND_CREATE_WITH_REASON = [
    InfeasibleNavigateAndCreateUserWithReasonTask,
    InfeasibleNavigateAndCreateIncidentWithReasonTask,
    InfeasibleNavigateAndCreateChangeRequestWithReasonTask,
    InfeasibleNavigateAndCreateProblemWithReasonTask,
    InfeasibleNavigateAndCreateHardwareAssetWithReasonTask,
]
INFEASIBLE_NAVIGATE_AND_CREATE = [


            The start of the task description to be completed. Provided by the child class.
        short_description: str
            A short description of the task to be completed. "Create a new user". Provided by the child class.
        """
        assert level in [2, 3], "Level must be either 2 or 3"
        self.level = level
        super().__init__(
            seed=seed,
            instance=instance,
            fixed_config=fixed_config,
            level=level,
        )
        self.used_in_level_2 = self.level == 2
        self.task_class = task_class
        self.task_description = None
        self.short_description = None
        # Get the navigation configuration; there is only one configuration for each application and module combo
        self.navigation_config = navigation_config
        self.function = partial(function, provide_reason=provide_reason)

    def setup_goal(self, page: Page) -> tuple[str, dict]:
        config = self.fixed_config if self.fixed_config else self._get_config()
        goal, info = super().setup_goal(page=page, config=config)

        return goal, info

    def _get_config(self) -> list[AbstractServiceNowTask]:
        valid_task_config = self.random.choice(self.task_class.all_configs())
        infeasible_task_config, self.infeasible_reasons = self.function(
            config=valid_task_config, random=self.random
        )
        config = [
            # Infeasible version of navigate to the task start page
            AllMenuTask(
                instance=self.instance,
                fixed_config=self.navigation_config,
                is_validated=False,
                used_in_level_2=True,
                has_description=True,
            ),
            self.task_class(
                seed=self.seed,
                instance=self.instance,
                fixed_config=infeasible_task_config,
                is_validated=False,


        super().__init__(
            seed=seed,
            instance=instance,
            fixed_config=fixed_config,
            level=level,
        )
        self.used_in_level_2 = self.level == 2
        self.task_class = task_class
        self.task_description = None
        self.short_description = None
        # Get the navigation configuration; there is only one configuration for each application and module combo
        self.navigation_config = navigation_config
        self.function = partial(function, provide_reason=provide_reason)

    def setup_goal(self, page: Page) -> tuple[str, dict]:
        config = self.fixed_config if self.fixed_config else self._get_config()
        goal, info = super().setup_goal(page=page, config=config)

        return goal, info

    def _get_config(self) -> list[AbstractServiceNowTask]:
        valid_task_config = self.random.choice(self.task_class.all_configs())
        infeasible_task_config, self.infeasible_reasons = self.function(
            config=valid_task_config, random=self.random
        )
        config = [
            # Infeasible version of navigate to the task start page
            AllMenuTask(
                instance=self.instance,
                fixed_config=self.navigation_config,
                is_validated=False,
                used_in_level_2=True,
                has_description=True,
            ),
            self.task_class(
                seed=self.seed,
                instance=self.instance,
                fixed_config=infeasible_task_config,
                is_validated=False,
                has_description=True,
                used_in_level_2=self.used_in_level_2,
            ),
        ]

        return config

class InfeasibleNavigateAndCreateUserWithReasonTask(InfeasibleNavigateAndDoTask):
    def __init__(
        self,
        seed: int = None,
        instance: SNowInstance = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Infeasible version of navigate to the user list page and create a new user.

        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a new user"
        """


import faker

faker = faker.Faker()
import json

from playwright.sync_api import Page
from typing import List, Tuple

from .base import AbstractServiceNowTask

from ..utils.utils import check_url_suffix_match

from ...api.utils import db_delete_from_table, table_api_call

class DeleteRecordTask(AbstractServiceNowTask):
    """
    Delete a record from a list.

    Parameters:
    -----------
    instance: SNowInstance
        The instance to use.
    start_rel_url: str
        The relative URL of the list containing the record to delete.
    list_name: str
        The displayed name of the list containing the record to delete.
    fixed_config: dict
        Configuration to use for the task. If provided, the task will use the provided configuration instead of
        selecting a random one. See browsergym/workarena/data_files/task_configs/filter_change_request_list_task.json
        for an example of a configuration file.
    all_configs: list[dict]
        A list of all possible configurations to use for the task.
    record_sys_id: str
        The sys_id of the record to delete. If not provided, a record will be created during the setup.
    record_number: str
        The number of the record to delete; used in the cheat. If not provided, the cheat will select the last one.
    """

    def __init__(
        self,
        seed: int = None,
        instance=None,
        start_rel_url: str = "",
        list_name: str = "",
        fixed_config: dict = None,
        all_configs: list[dict] = None,
        record_sys_id: str = None,
        record_number: str = None,
        **kwargs,
    ) -> None:
        super().__init__(seed=seed, instance=instance, start_rel_url=start_rel_url)
        self.list_name = list_name
        self.table_name = start_rel_url.split("/")[-1].split("_list.do")[0]
        self.fixed_config = fixed_config
        self.config = None
        self.pretty_printed_field_name = None
        self.field_name = None
        self.field_value = None
        self.other_fields = None
        self.all_configs = all_configs
        # If the record_sys_id is not provided, it will be created during the setup
        self.record_sys_id = record_sys_id
        self.record_number = record_number
        self.__dict__.update(kwargs)

    def setup_goal(self, page: Page) -> tuple[str, dict]:
        self.config = (
            self.fixed_config if self.fixed_config else self.random.choice(self.all_configs)
        )
        self.field_name = self.config.get("field_name")
        self.pretty_printed_field_name = self.config.get("pretty_printed_field_name")
        self.field_value = self.config.get("field_value")
        self.other_fields = self.config.get("other_fields")
        if self.record_sys_id is None:
            # First, check if the record already exists
            record = table_api_call(
                instance=self.instance,
                table=self.table_name,
                params={
                    "sysparm_query": f"{self.field_name}={self.field_value}",
                    "sysparm_fields": "sys_id",
                },
            )["result"]
            if len(record) > 0:
                raise ValueError(
                    f"Record already with {self.field_name} = {self.field_value} exists. Please delete it before proceeding."
                )

            self.record_sys_id = table_api_call(
                instance=self.instance,
                table=self.table_name,
                data=json.dumps(
                    {
                        self.field_name: self.field_value,
                        **self.other_fields,
                    }
                ),
                method="POST",
            )["result"]["sys_id"]

        goal = self.get_pretty_printed_description()

        return goal, {}

    def get_init_scripts(self) -> List[str]:
        return super().get_init_scripts() + ["registerGsftMainLoaded();"]

    def get_pretty_printed_description(self) -> str:
        """
        Get the task info for this task when used in a private task; Used in L3 compositional tasks.
        called by subclasses
        """
        task_info = f"- Delete the record with {self.pretty_printed_field_name}={self.field_value} from the {self.list_name} list."

        return task_info

    def cheat(self, page: Page, chat_messages: list[str]) -> None:
        super().cheat(page, chat_messages)
        frame = page.wait_for_selector('iframe[name="gsft_main"]').content_frame()

        # If the record number is provided, click on the record with that number...
        if self.record_number is not None:
            frame.locator(f"[aria-label='Preview record: {self.record_number}']").click()
            page.wait_for_timeout(500)
            frame.get_by_text("Open Record").click()
        # ....Otherwise, otherwise filter the list and click on the record
        else:
            # Search for the record
            frame.get_by_label(
                f"Search a specific field of the {self.list_name} list"
            ).select_option(f"{self.field_name}")
            search_input = frame.locator('input[aria-label="Search"]')
            search_input.click()
            search_input.fill(self.field_value)
            search_input.press("Enter")
            page.wait_for_function(
                "typeof window.gsft_main !== 'undefined' && window.gsft_main.WORKARENA_LOAD_COMPLETE"
            )
            # Click on the record to open it
            # The first 2 displays of the record are in the search bar; the 3rd and last will be the link to open it
            frame.get_by_label(self.field_value).last.click()

        page.wait_for_function(
            "typeof window.gsft_main !== 'undefined' && window.gsft_main.WORKARENA_LOAD_COMPLETE"
        )
        frame = page.wait_for_selector('iframe[name="gsft_main"]').content_frame()
        # Click on delete, then confirm delete in the popup
        frame.get_by_text("delete").first.click()
        frame.wait_for_selector('header[aria-label="Confirmation"]')
        page.keyboard.press("Enter")
        # Wait for record to be updated in the DB
        record_deleted = False
        while not record_deleted:
            record = table_api_call(
                instance=self.instance,
                table=self.table_name,
                params={
                    "sysparm_query": f"{self.field_name}={self.field_value}",
                    "sysparm_fields": "sys_id",
                },
            )["result"]
            record_deleted = len(record) == 0
        page.wait_for_timeout(3000)

    def validate(self, page: Page, chat_messages: list[str]) -> Tuple[float, bool, str, dict]:
        """
        Validate the solution
        """
        record = table_api_call(
            instance=self.instance,
            table=self.table_name,
            params={"sysparm_query": f"{self.field_name}={self.field_value}"},
        )["result"]
        if len(record) > 0:
            return 0, False, "", {"message": "Record was not deleted."}

        return 1, True, "Nice work, thank you!", {"message": "Record was deleted successfully."}

    def teardown(self) -> None:
        super().teardown()
        result = table_api_call(
            instance=self.instance,
            table=self.table_name,
            params={
                "sysparm_query": f"{self.field_name}={self.field_value}",
                "sysparm_fields": "sys_id",
            },
        )
        if len(result["result"]) > 0:
            db_delete_from_table(
                instance=self.instance,
                table=self.table_name,
                sys_id=self.record_sys_id,
            )

class DeleteUserTask(DeleteRecordTask):
    def __init__(self, instance=None, fixed_config=None, record_sys_id=None, **kwargs) -> None:
        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/sys_user_list.do",
            list_name="Users",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        if fixed_config is None:
            first_name = faker.first_name()
            last_name = faker.last_name()
            email = first_name.lower() + "." + last_name.lower() + "@workarena.com"
            self.fixed_config = {
                "field_name": "user_name",
                "pretty_printed_field_name": "User ID",
                "field_value": first_name + " " + last_name,
                "other_fields": {"email": email},
            }

class DeleteExpenseLineExpenseManagementTask(DeleteRecordTask):
    """
    Delete one row from the expense lines list

    Args:
    --------
    goal_type (str):
        The type of goal to generate. Choice of "base", "date", "amount", "any"
    level (int):
        The level of the task
    skip_description (bool):
        Whether to skip the description of the task

    """

    def __init__(
        self,
        instance=None,
        fixed_config=None,
        record_sys_id=None,
        goal_type="base",
        level=2,
        skip_description=False,
        **kwargs,
    ) -> None:
        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/fm_expense_line_list.do",
            list_name="Expense Lines",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        self.goal_type = goal_type
        self.level = level
        self.skip_description = skip_description

    def get_pretty_printed_description(self) -> str:
        """
        Get the task info for this task when used in a private task; Used in compositional tasks.
        called by subclasses
        """
        task_info = f"Delete expense lines with duplicated short descriptions"
        if self.skip_description:
            task_info = ""
        elif self.level == 3:
            task_info += f" according to the protocol."
        elif self.goal_type == "base":
            task_info += f" where the duplicated expense lines are not associated with tasks."
        elif self.goal_type == "date":
            task_info += f", keeping only the one that has the oldest date."
        elif self.goal_type == "amount":
            task_info += f", keeping only the most expensive duplicate."
        elif self.goal_type == "any":
            task_info += f", keeping only one."

        return task_info

class DeleteExpenseLineKnapsack(DeleteRecordTask):
    """
    Delete one row from the expense lines list

    Args:
    --------
    goal_type (str):
        The type of goal to generate. Choice of "base", "date", "amount", "any"
    answer_format (str):
        The type of answer to generate. Choice of total_return_only, total_return_and_investments, investments_only, cleanup, cleanup_and_return
    level (int):
        The level of the task
    skip_description (bool):
        Whether to skip the description of the task

    """

    def __init__(
        self,
        instance=None,
        fixed_config=None,
        record_sys_id=None,
        goal_type="base",
        level=2,
        answer_format=None,
        skip_description=False,
        **kwargs,
    ) -> None:
        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/fm_expense_line_list.do",
            list_name="Expense Lines",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        self.goal_type = goal_type
        self.level = level
        self.answer_format = answer_format
        self.skip_description = skip_description

    def get_pretty_printed_description(self) -> str:
        if self.skip_description:
            return ""
        if self.level == 3:
            task_info = "Allocate the budget to maximize revenue."
        elif self.level == 2:
            task_info = f"Allocate the budget to maximize revenue. This involves going over expense lines and identifying the ones maximizing revenue while fitting in the allowed budget of {self.budget}. The returns are written in their short description."
            if self.answer_format == "total_return_only":
                task_info += " Provide only the total return of the investments in the chat."
            if self.answer_format == "total_return_and_investments":
                task_info += " Provide the total return of the investments as well as the number of the investments in the chat."
            if self.answer_format == "investments_only":
                task_info += " Provide only the numbers of the investments in the chat."
            if self.answer_format == "cleanup":
                task_info += " Delete the investments that will not be kept so that only the selected investments remain."
            if self.answer_format == "cleanup_and_return":
                task_info += " Delete the investments that will not be kept so that only the selected investments remain as well as returning their total value in the chat."

        return task_info

__TASKS__ = [DeleteUserTask]


DeleteRecordTask

import faker

faker = faker.Faker()
import json

from playwright.sync_api import Page
from typing import List, Tuple

from .base import AbstractServiceNowTask

from ..utils.utils import check_url_suffix_match

from ...api.utils import db_delete_from_table, table_api_call

class DeleteRecordTask(AbstractServiceNowTask):
    """
    Delete a record from a list.

    Parameters:
    -----------
    instance: SNowInstance
        The instance to use.
    start_rel_url: str
        The relative URL of the list containing the record to delete.
    list_name: str
        The displayed name of the list containing the record to delete.
    fixed_config: dict
        Configuration to use for the task. If provided, the task will use the provided configuration instead of
        selecting a random one. See browsergym/workarena/data_files/task_configs/filter_change_request_list_task.json
        for an example of a configuration file.
    all_configs: list[dict]
        A list of all possible configurations to use for the task.
    record_sys_id: str
        The sys_id of the record to delete. If not provided, a record will be created during the setup.
    record_number: str
        The number of the record to delete; used in the cheat. If not provided, the cheat will select the last one.
    """

    def __init__(
        self,
        seed: int = None,
        instance=None,
        start_rel_url: str = "",
        list_name: str = "",
        fixed_config: dict = None,
        all_configs: list[dict] = None,
        record_sys_id: str = None,
        record_number: str = None,
        **kwargs,
    ) -> None:
        super().__init__(seed=seed, instance=instance, start_rel_url=start_rel_url)
        self.list_name = list_name
        self.table_name = start_rel_url.split("/")[-1].split("_list.do")[0]
        self.fixed_config = fixed_config
        self.config = None
        self.pretty_printed_field_name = None
        self.field_name = None
        self.field_value = None
        self.other_fields = None
        self.all_configs = all_configs
        # If the record_sys_id is not provided, it will be created during the setup
        self.record_sys_id = record_sys_id
        self.record_number = record_number
        self.__dict__.update(kwargs)

    def setup_goal(self, page: Page) -> tuple[str, dict]:
        self.config = (
            self.fixed_config if self.fixed_config else self.random.choice(self.all_configs)
        )
        self.field_name = self.config.get("field_name")
        self.pretty_printed_field_name = self.config.get("pretty_printed_field_name")
        self.field_value = self.config.get("field_value")
        self.other_fields = self.config.get("other_fields")
        if self.record_sys_id is None:
            # First, check if the record already exists
            record = table_api_call(
                instance=self.instance,
                table=self.table_name,
                params={
                    "sysparm_query": f"{self.field_name}={self.field_value}",
                    "sysparm_fields": "sys_id",
                },
            )["result"]
            if len(record) > 0:
                raise ValueError(
                    f"Record already with {self.field_name} = {self.field_value} exists. Please delete it before proceeding."
                )

            self.record_sys_id = table_api_call(
                instance=self.instance,
                table=self.table_name,
                data=json.dumps(
                    {
                        self.field_name: self.field_value,
                        **self.other_fields,
                    }
                ),
                method="POST",
            )["result"]["sys_id"]

        goal = self.get_pretty_printed_description()

        return goal, {}

    def get_init_scripts(self) -> List[str]:
        return super().get_init_scripts() + ["registerGsftMainLoaded();"]

    def get_pretty_printed_description(self) -> str:
        """
        Get the task info for this task when used in a private task; Used in L3 compositional tasks.
        called by subclasses
        """
        task_info = f"- Delete the record with {self.pretty_printed_field_name}={self.field_value} from the {self.list_name} list."

        return task_info

    def cheat(self, page: Page, chat_messages: list[str]) -> None:
        super().cheat(page, chat_messages)
        frame = page.wait_for_selector('iframe[name="gsft_main"]').content_frame()

        # If the record number is provided, click on the record with that number...
        if self.record_number is not None:
            frame.locator(f"[aria-label='Preview record: {self.record_number}']").click()
            page.wait_for_timeout(500)
            frame.get_by_text("Open Record").click()
        # ....Otherwise, otherwise filter the list and click on the record
        else:
            # Search for the record
            frame.get_by_label(
                f"Search a specific field of the {self.list_name} list"
            ).select_option(f"{self.field_name}")
            search_input = frame.locator('input[aria-label="Search"]')
            search_input.click()
            search_input.fill(self.field_value)
            search_input.press("Enter")
            page.wait_for_function(
                "typeof window.gsft_main !== 'undefined' && window.gsft_main.WORKARENA_LOAD_COMPLETE"
            )
            # Click on the record to open it
            # The first 2 displays of the record are in the search bar; the 3rd and last will be the link to open it
            frame.get_by_label(self.field_value).last.click()

        page.wait_for_function(
            "typeof window.gsft_main !== 'undefined' && window.gsft_main.WORKARENA_LOAD_COMPLETE"
        )
        frame = page.wait_for_selector('iframe[name="gsft_main"]').content_frame()
        # Click on delete, then confirm delete in the popup
        frame.get_by_text("delete").first.click()
        frame.wait_for_selector('header[aria-label="Confirmation"]')
        page.keyboard.press("Enter")
        # Wait for record to be updated in the DB
        record_deleted = False
        while not record_deleted:
            record = table_api_call(
                instance=self.instance,
                table=self.table_name,
                params={
                    "sysparm_query": f"{self.field_name}={self.field_value}",
                    "sysparm_fields": "sys_id",
                },
            )["result"]
            record_deleted = len(record) == 0
        page.wait_for_timeout(3000)

    def validate(self, page: Page, chat_messages: list[str]) -> Tuple[float, bool, str, dict]:
        """
        Validate the solution
        """
        record = table_api_call(
            instance=self.instance,
            table=self.table_name,
            params={"sysparm_query": f"{self.field_name}={self.field_value}"},
        )["result"]
        if len(record) > 0:
            return 0, False, "", {"message": "Record was not deleted."}

        return 1, True, "Nice work, thank you!", {"message": "Record was deleted successfully."}

    def teardown(self) -> None:
        super().teardown()
        result = table_api_call(
            instance=self.instance,
            table=self.table_name,
            params={
                "sysparm_query": f"{self.field_name}={self.field_value}",
                "sysparm_fields": "sys_id",
            },
        )
        if len(result["result"]) > 0:
            db_delete_from_table(
                instance=self.instance,
                table=self.table_name,
                sys_id=self.record_sys_id,
            )

class DeleteUserTask(DeleteRecordTask):
    def __init__(self, instance=None, fixed_config=None, record_sys_id=None, **kwargs) -> None:
        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/sys_user_list.do",
            list_name="Users",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        if fixed_config is None:
            first_name = faker.first_name()
            last_name = faker.last_name()
            email = first_name.lower() + "." + last_name.lower() + "@workarena.com"
            self.fixed_config = {
                "field_name": "user_name",
                "pretty_printed_field_name": "User ID",
                "field_value": first_name + " " + last_name,


DeleteUserTask

        return 1, True, "Nice work, thank you!", {"message": "Record was deleted successfully."}

    def teardown(self) -> None:
        super().teardown()
        result = table_api_call(
            instance=self.instance,
            table=self.table_name,
            params={
                "sysparm_query": f"{self.field_name}={self.field_value}",
                "sysparm_fields": "sys_id",
            },
        )
        if len(result["result"]) > 0:
            db_delete_from_table(
                instance=self.instance,
                table=self.table_name,
                sys_id=self.record_sys_id,
            )

class DeleteUserTask(DeleteRecordTask):
    def __init__(self, instance=None, fixed_config=None, record_sys_id=None, **kwargs) -> None:
        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/sys_user_list.do",
            list_name="Users",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        if fixed_config is None:
            first_name = faker.first_name()
            last_name = faker.last_name()
            email = first_name.lower() + "." + last_name.lower() + "@workarena.com"
            self.fixed_config = {
                "field_name": "user_name",
                "pretty_printed_field_name": "User ID",
                "field_value": first_name + " " + last_name,
                "other_fields": {"email": email},
            }

class DeleteExpenseLineExpenseManagementTask(DeleteRecordTask):
    """
    Delete one row from the expense lines list

    Args:
    --------
    goal_type (str):
        The type of goal to generate. Choice of "base", "date", "amount", "any"
    level (int):
        The level of the task
    skip_description (bool):
        Whether to skip the description of the task

    """

    def __init__(
        self,
        instance=None,


DeleteExpenseLineExpenseManagementTask

        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/sys_user_list.do",
            list_name="Users",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        if fixed_config is None:
            first_name = faker.first_name()
            last_name = faker.last_name()
            email = first_name.lower() + "." + last_name.lower() + "@workarena.com"
            self.fixed_config = {
                "field_name": "user_name",
                "pretty_printed_field_name": "User ID",
                "field_value": first_name + " " + last_name,
                "other_fields": {"email": email},
            }

class DeleteExpenseLineExpenseManagementTask(DeleteRecordTask):
    """
    Delete one row from the expense lines list

    Args:
    --------
    goal_type (str):
        The type of goal to generate. Choice of "base", "date", "amount", "any"
    level (int):
        The level of the task
    skip_description (bool):
        Whether to skip the description of the task

    """

    def __init__(
        self,
        instance=None,
        fixed_config=None,
        record_sys_id=None,
        goal_type="base",
        level=2,
        skip_description=False,
        **kwargs,
    ) -> None:
        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/fm_expense_line_list.do",
            list_name="Expense Lines",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        self.goal_type = goal_type
        self.level = level
        self.skip_description = skip_description

    def get_pretty_printed_description(self) -> str:
        """
        Get the task info for this task when used in a private task; Used in compositional tasks.
        called by subclasses
        """
        task_info = f"Delete expense lines with duplicated short descriptions"
        if self.skip_description:
            task_info = ""
        elif self.level == 3:
            task_info += f" according to the protocol."
        elif self.goal_type == "base":
            task_info += f" where the duplicated expense lines are not associated with tasks."
        elif self.goal_type == "date":
            task_info += f", keeping only the one that has the oldest date."
        elif self.goal_type == "amount":
            task_info += f", keeping only the most expensive duplicate."
        elif self.goal_type == "any":
            task_info += f", keeping only one."

        return task_info

class DeleteExpenseLineKnapsack(DeleteRecordTask):
    """
    Delete one row from the expense lines list

    Args:
    --------
    goal_type (str):
        The type of goal to generate. Choice of "base", "date", "amount", "any"
    answer_format (str):
        The type of answer to generate. Choice of total_return_only, total_return_and_investments, investments_only, cleanup, cleanup_and_return
    level (int):
        The level of the task
    skip_description (bool):
        Whether to skip the description of the task

    """

    def __init__(


DeleteExpenseLineKnapsack

        Get the task info for this task when used in a private task; Used in compositional tasks.
        called by subclasses
        """
        task_info = f"Delete expense lines with duplicated short descriptions"
        if self.skip_description:
            task_info = ""
        elif self.level == 3:
            task_info += f" according to the protocol."
        elif self.goal_type == "base":
            task_info += f" where the duplicated expense lines are not associated with tasks."
        elif self.goal_type == "date":
            task_info += f", keeping only the one that has the oldest date."
        elif self.goal_type == "amount":
            task_info += f", keeping only the most expensive duplicate."
        elif self.goal_type == "any":
            task_info += f", keeping only one."

        return task_info

class DeleteExpenseLineKnapsack(DeleteRecordTask):
    """
    Delete one row from the expense lines list

    Args:
    --------
    goal_type (str):
        The type of goal to generate. Choice of "base", "date", "amount", "any"
    answer_format (str):
        The type of answer to generate. Choice of total_return_only, total_return_and_investments, investments_only, cleanup, cleanup_and_return
    level (int):
        The level of the task
    skip_description (bool):
        Whether to skip the description of the task

    """

    def __init__(
        self,
        instance=None,
        fixed_config=None,
        record_sys_id=None,
        goal_type="base",
        level=2,
        answer_format=None,
        skip_description=False,
        **kwargs,
    ) -> None:
        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/fm_expense_line_list.do",
            list_name="Expense Lines",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        self.goal_type = goal_type
        self.level = level
        self.answer_format = answer_format
        self.skip_description = skip_description

    def get_pretty_printed_description(self) -> str:
        if self.skip_description:
            return ""
        if self.level == 3:
            task_info = "Allocate the budget to maximize revenue."
        elif self.level == 2:
            task_info = f"Allocate the budget to maximize revenue. This involves going over expense lines and identifying the ones maximizing revenue while fitting in the allowed budget of {self.budget}. The returns are written in their short description."
            if self.answer_format == "total_return_only":
                task_info += " Provide only the total return of the investments in the chat."
            if self.answer_format == "total_return_and_investments":
                task_info += " Provide the total return of the investments as well as the number of the investments in the chat."
            if self.answer_format == "investments_only":
                task_info += " Provide only the numbers of the investments in the chat."
            if self.answer_format == "cleanup":
                task_info += " Delete the investments that will not be kept so that only the selected investments remain."
            if self.answer_format == "cleanup_and_return":
                task_info += " Delete the investments that will not be kept so that only the selected investments remain as well as returning their total value in the chat."

        return task_info

__TASKS__ = [DeleteUserTask]


        return task_info

class DeleteExpenseLineKnapsack(DeleteRecordTask):
    """
    Delete one row from the expense lines list

    Args:
    --------
    goal_type (str):
        The type of goal to generate. Choice of "base", "date", "amount", "any"
    answer_format (str):
        The type of answer to generate. Choice of total_return_only, total_return_and_investments, investments_only, cleanup, cleanup_and_return
    level (int):
        The level of the task
    skip_description (bool):
        Whether to skip the description of the task

    """

    def __init__(
        self,
        instance=None,
        fixed_config=None,
        record_sys_id=None,
        goal_type="base",
        level=2,
        answer_format=None,
        skip_description=False,
        **kwargs,
    ) -> None:
        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/fm_expense_line_list.do",
            list_name="Expense Lines",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        self.goal_type = goal_type
        self.level = level
        self.answer_format = answer_format
        self.skip_description = skip_description

    def get_pretty_printed_description(self) -> str:
        if self.skip_description:
            return ""
        if self.level == 3:
            task_info = "Allocate the budget to maximize revenue."
        elif self.level == 2:
            task_info = f"Allocate the budget to maximize revenue. This involves going over expense lines and identifying the ones maximizing revenue while fitting in the allowed budget of {self.budget}. The returns are written in their short description."
            if self.answer_format == "total_return_only":
                task_info += " Provide only the total return of the investments in the chat."
            if self.answer_format == "total_return_and_investments":
                task_info += " Provide the total return of the investments as well as the number of the investments in the chat."
            if self.answer_format == "investments_only":
                task_info += " Provide only the numbers of the investments in the chat."
            if self.answer_format == "cleanup":
                task_info += " Delete the investments that will not be kept so that only the selected investments remain."
            if self.answer_format == "cleanup_and_return":
                task_info += " Delete the investments that will not be kept so that only the selected investments remain as well as returning their total value in the chat."

        return task_info


        all_configs: list[dict] = None,
        record_sys_id: str = None,
        record_number: str = None,
        **kwargs,
    ) -> None:
        super().__init__(seed=seed, instance=instance, start_rel_url=start_rel_url)
        self.list_name = list_name
        self.table_name = start_rel_url.split("/")[-1].split("_list.do")[0]
        self.fixed_config = fixed_config
        self.config = None
        self.pretty_printed_field_name = None
        self.field_name = None
        self.field_value = None
        self.other_fields = None
        self.all_configs = all_configs
        # If the record_sys_id is not provided, it will be created during the setup
        self.record_sys_id = record_sys_id
        self.record_number = record_number
        self.__dict__.update(kwargs)

    def setup_goal(self, page: Page) -> tuple[str, dict]:
        self.config = (
            self.fixed_config if self.fixed_config else self.random.choice(self.all_configs)
        )
        self.field_name = self.config.get("field_name")
        self.pretty_printed_field_name = self.config.get("pretty_printed_field_name")
        self.field_value = self.config.get("field_value")
        self.other_fields = self.config.get("other_fields")
        if self.record_sys_id is None:
            # First, check if the record already exists
            record = table_api_call(
                instance=self.instance,
                table=self.table_name,
                params={
                    "sysparm_query": f"{self.field_name}={self.field_value}",
                    "sysparm_fields": "sys_id",
                },
            )["result"]
            if len(record) > 0:
                raise ValueError(
                    f"Record already with {self.field_name} = {self.field_value} exists. Please delete it before proceeding."
                )

            self.record_sys_id = table_api_call(
                instance=self.instance,
                table=self.table_name,
                data=json.dumps(
                    {
                        self.field_name: self.field_value,
                        **self.other_fields,
                    }
                ),
                method="POST",
            )["result"]["sys_id"]

        goal = self.get_pretty_printed_description()

        return goal, {}

    def get_init_scripts(self) -> List[str]:
        return super().get_init_scripts() + ["registerGsftMainLoaded();"]

    def get_pretty_printed_description(self) -> str:
        """
        Get the task info for this task when used in a private task; Used in L3 compositional tasks.
        called by subclasses
        """
        task_info = f"- Delete the record with {self.pretty_printed_field_name}={self.field_value} from the {self.list_name} list."

        return task_info

    def cheat(self, page: Page, chat_messages: list[str]) -> None:
        super().cheat(page, chat_messages)
        frame = page.wait_for_selector('iframe[name="gsft_main"]').content_frame()

        # If the record number is provided, click on the record with that number...
        if self.record_number is not None:
            frame.locator(f"[aria-label='Preview record: {self.record_number}']").click()


                raise ValueError(
                    f"Record already with {self.field_name} = {self.field_value} exists. Please delete it before proceeding."
                )

            self.record_sys_id = table_api_call(
                instance=self.instance,
                table=self.table_name,
                data=json.dumps(
                    {
                        self.field_name: self.field_value,
                        **self.other_fields,
                    }
                ),
                method="POST",
            )["result"]["sys_id"]

        goal = self.get_pretty_printed_description()

        return goal, {}

    def get_init_scripts(self) -> List[str]:
        return super().get_init_scripts() + ["registerGsftMainLoaded();"]

    def get_pretty_printed_description(self) -> str:
        """
        Get the task info for this task when used in a private task; Used in L3 compositional tasks.
        called by subclasses
        """
        task_info = f"- Delete the record with {self.pretty_printed_field_name}={self.field_value} from the {self.list_name} list."

        return task_info

    def cheat(self, page: Page, chat_messages: list[str]) -> None:
        super().cheat(page, chat_messages)
        frame = page.wait_for_selector('iframe[name="gsft_main"]').content_frame()

        # If the record number is provided, click on the record with that number...
        if self.record_number is not None:
            frame.locator(f"[aria-label='Preview record: {self.record_number}']").click()
            page.wait_for_timeout(500)
            frame.get_by_text("Open Record").click()
        # ....Otherwise, otherwise filter the list and click on the record


        record_sys_id=None,
        goal_type="base",
        level=2,
        answer_format=None,
        skip_description=False,
        **kwargs,
    ) -> None:
        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/fm_expense_line_list.do",
            list_name="Expense Lines",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        self.goal_type = goal_type
        self.level = level
        self.answer_format = answer_format
        self.skip_description = skip_description

    def get_pretty_printed_description(self) -> str:
        if self.skip_description:
            return ""
        if self.level == 3:
            task_info = "Allocate the budget to maximize revenue."
        elif self.level == 2:
            task_info = f"Allocate the budget to maximize revenue. This involves going over expense lines and identifying the ones maximizing revenue while fitting in the allowed budget of {self.budget}. The returns are written in their short description."
            if self.answer_format == "total_return_only":
                task_info += " Provide only the total return of the investments in the chat."
            if self.answer_format == "total_return_and_investments":
                task_info += " Provide the total return of the investments as well as the number of the investments in the chat."
            if self.answer_format == "investments_only":
                task_info += " Provide only the numbers of the investments in the chat."
            if self.answer_format == "cleanup":
                task_info += " Delete the investments that will not be kept so that only the selected investments remain."
            if self.answer_format == "cleanup_and_return":
                task_info += " Delete the investments that will not be kept so that only the selected investments remain as well as returning their total value in the chat."

        return task_info

__TASKS__ = [DeleteUserTask]


cheat

                ),
                method="POST",
            )["result"]["sys_id"]

        goal = self.get_pretty_printed_description()

        return goal, {}

    def get_init_scripts(self) -> List[str]:
        return super().get_init_scripts() + ["registerGsftMainLoaded();"]

    def get_pretty_printed_description(self) -> str:
        """
        Get the task info for this task when used in a private task; Used in L3 compositional tasks.
        called by subclasses
        """
        task_info = f"- Delete the record with {self.pretty_printed_field_name}={self.field_value} from the {self.list_name} list."

        return task_info

    def cheat(self, page: Page, chat_messages: list[str]) -> None:
        super().cheat(page, chat_messages)
        frame = page.wait_for_selector('iframe[name="gsft_main"]').content_frame()

        # If the record number is provided, click on the record with that number...
        if self.record_number is not None:
            frame.locator(f"[aria-label='Preview record: {self.record_number}']").click()
            page.wait_for_timeout(500)
            frame.get_by_text("Open Record").click()
        # ....Otherwise, otherwise filter the list and click on the record
        else:
            # Search for the record
            frame.get_by_label(
                f"Search a specific field of the {self.list_name} list"
            ).select_option(f"{self.field_name}")
            search_input = frame.locator('input[aria-label="Search"]')
            search_input.click()
            search_input.fill(self.field_value)
            search_input.press("Enter")
            page.wait_for_function(
                "typeof window.gsft_main !== 'undefined' && window.gsft_main.WORKARENA_LOAD_COMPLETE"
            )
            # Click on the record to open it
            # The first 2 displays of the record are in the search bar; the 3rd and last will be the link to open it
            frame.get_by_label(self.field_value).last.click()

        page.wait_for_function(
            "typeof window.gsft_main !== 'undefined' && window.gsft_main.WORKARENA_LOAD_COMPLETE"
        )
        frame = page.wait_for_selector('iframe[name="gsft_main"]').content_frame()
        # Click on delete, then confirm delete in the popup
        frame.get_by_text("delete").first.click()
        frame.wait_for_selector('header[aria-label="Confirmation"]')
        page.keyboard.press("Enter")
        # Wait for record to be updated in the DB
        record_deleted = False
        while not record_deleted:
            record = table_api_call(
                instance=self.instance,
                table=self.table_name,
                params={
                    "sysparm_query": f"{self.field_name}={self.field_value}",
                    "sysparm_fields": "sys_id",
                },
            )["result"]
            record_deleted = len(record) == 0
        page.wait_for_timeout(3000)

    def validate(self, page: Page, chat_messages: list[str]) -> Tuple[float, bool, str, dict]:
        """
        Validate the solution
        """
        record = table_api_call(
            instance=self.instance,
            table=self.table_name,
            params={"sysparm_query": f"{self.field_name}={self.field_value}"},
        )["result"]
        if len(record) > 0:
            return 0, False, "", {"message": "Record was not deleted."}

        return 1, True, "Nice work, thank you!", {"message": "Record was deleted successfully."}

    def teardown(self) -> None:
        super().teardown()
        result = table_api_call(
            instance=self.instance,
            table=self.table_name,


validate

        )
        frame = page.wait_for_selector('iframe[name="gsft_main"]').content_frame()
        # Click on delete, then confirm delete in the popup
        frame.get_by_text("delete").first.click()
        frame.wait_for_selector('header[aria-label="Confirmation"]')
        page.keyboard.press("Enter")
        # Wait for record to be updated in the DB
        record_deleted = False
        while not record_deleted:
            record = table_api_call(
                instance=self.instance,
                table=self.table_name,
                params={
                    "sysparm_query": f"{self.field_name}={self.field_value}",
                    "sysparm_fields": "sys_id",
                },
            )["result"]
            record_deleted = len(record) == 0
        page.wait_for_timeout(3000)

    def validate(self, page: Page, chat_messages: list[str]) -> Tuple[float, bool, str, dict]:
        """
        Validate the solution
        """
        record = table_api_call(
            instance=self.instance,
            table=self.table_name,
            params={"sysparm_query": f"{self.field_name}={self.field_value}"},
        )["result"]
        if len(record) > 0:
            return 0, False, "", {"message": "Record was not deleted."}

        return 1, True, "Nice work, thank you!", {"message": "Record was deleted successfully."}

    def teardown(self) -> None:
        super().teardown()
        result = table_api_call(
            instance=self.instance,
            table=self.table_name,
            params={
                "sysparm_query": f"{self.field_name}={self.field_value}",
                "sysparm_fields": "sys_id",
            },
        )
        if len(result["result"]) > 0:
            db_delete_from_table(
                instance=self.instance,
                table=self.table_name,
                sys_id=self.record_sys_id,
            )

class DeleteUserTask(DeleteRecordTask):


teardown

                    "sysparm_fields": "sys_id",
                },
            )["result"]
            record_deleted = len(record) == 0
        page.wait_for_timeout(3000)

    def validate(self, page: Page, chat_messages: list[str]) -> Tuple[float, bool, str, dict]:
        """
        Validate the solution
        """
        record = table_api_call(
            instance=self.instance,
            table=self.table_name,
            params={"sysparm_query": f"{self.field_name}={self.field_value}"},
        )["result"]
        if len(record) > 0:
            return 0, False, "", {"message": "Record was not deleted."}

        return 1, True, "Nice work, thank you!", {"message": "Record was deleted successfully."}

    def teardown(self) -> None:
        super().teardown()
        result = table_api_call(
            instance=self.instance,
            table=self.table_name,
            params={
                "sysparm_query": f"{self.field_name}={self.field_value}",
                "sysparm_fields": "sys_id",
            },
        )
        if len(result["result"]) > 0:
            db_delete_from_table(
                instance=self.instance,
                table=self.table_name,
                sys_id=self.record_sys_id,
            )

class DeleteUserTask(DeleteRecordTask):
    def __init__(self, instance=None, fixed_config=None, record_sys_id=None, **kwargs) -> None:
        super().__init__(
            instance=instance,
            start_rel_url="/now/nav/ui/classic/params/target/sys_user_list.do",
            list_name="Users",
            fixed_config=fixed_config,
            record_sys_id=record_sys_id,
            **kwargs,
        )
        if fixed_config is None:
            first_name = faker.first_name()
            last_name = faker.last_name()
            email = first_name.lower() + "." + last_name.lower() + "@workarena.com"
            self.fixed_config = {
                "field_name": "user_name",
                "pretty_printed_field_name": "User ID",
                "field_value": first_name + " " + last_name,


from playwright.sync_api._generated import Page
from typing import Tuple

from .dash_do_base import DashboardRetrieveIncidentAndDoTask, DashDoFinalTask

from ..base import AbstractServiceNowTask
from ..dashboard import SingleChartMinMaxRetrievalTask, SingleChartMeanMedianModeRetrievalTask

from ...api.utils import table_api_call, db_delete_from_table
from ...instance import SNowInstance

from browsergym.workarena.tasks.navigation import AllMenuTask
from browsergym.workarena.tasks.form import CreateProblemTask

class DashboardRetrieveIncidentAndCreateProblemTask(DashboardRetrieveIncidentAndDoTask):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
        question: str = None,
        dashboard_class: AbstractServiceNowTask = None,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question=question,
            dashboard_class=dashboard_class,
        )
        self.attribute_name = "assigned_to"
        self.filter_than = "lesser"
        self.prefix = "DCP"

    def set_compositional_task(self) -> None:
        agent_full_names, agent_value_sysids = self.get_agent_values(
            self.attribute_name, self.filter_than
        )
        self.agent_value_sysids = agent_value_sysids
        create_problem_subtasks = []
        self.short_description = "Compulsory training for employee in probation"
        for agent_full_name in agent_full_names:
            problem_config = {
                "fields": {
                    "short_description": "Problem statement",
                    "urgency": "Urgency",
                    "assigned_to": "Assigned to",
                    "impact": "Impact",
                },
                "task_fields": [
                    "short_description",
                    "urgency",
                    "assigned_to",
                    "impact",
                ],
                "template_record": {
                    "short_description": self.short_description,
                    "impact": "1 - High",
                    "urgency": "1 - High",
                    "assigned_to": agent_full_name,
                },
            }

            create_problem_subtask = [
                # Navigate to the incident list
                AllMenuTask(
                    instance=self.instance,
                    fixed_config={
                        "application": "Problem",
                        "module": "All",
                        "url": "/now/nav/ui/classic/params/target/problem_list.do",
                    },
                    is_validated=False,
                    used_in_level_2=True,
                ),
                # Create a problem
                CreateProblemTask(
                    instance=self.instance,
                    fixed_config=problem_config,
                    is_validated=False,
                    used_in_level_2=True,
                    check_record_created=False,
                ),
            ]
            create_problem_subtasks += create_problem_subtask

        self.compositional_task = create_problem_subtasks

    def setup_goal(self, page: Page) -> tuple[str, dict]:
        self.create_report(
            user_roles=[
                "itil",
                "problem_admin",
                "problem_manager",
                "problem_coordinator",
                "problem_task_analyst",
            ]
        )
        self.set_compositional_task()
        config = self.fixed_config if self.fixed_config else self._get_config()

        if self.level == 3:
            self.task_description = (
                self.task_description
                + f"\t - Please retrieve the '{self.description_mapping[self.question]}' value of the number of incidents assigned across agents. Retrieve agents that have less than or equal number of incidents assigned to them compared to this value.\n"
                + f"\t   For example, if you were asked to find the 'mean' or 'average' for a case where there are 4 agents assigned 1,2,3,2 incidents respectively, the mean would be 2. The list of agents required for solving the following task would be all the agents that have less than or equal to 2 assigned incidents.\n\n"
                + f"\t - Task: For each agent that fits the above criteria, create a 'problem' with the following information (only fill these fields) and assign it to them using the 'Assigned to' field: \n"
                + f"\t\t Impact: '1 - High', Urgency: '1 - High', Problem statement: 'Compulsory training for employee in probation'.\n"
                + f"Note that you will create as many problems as there are agents matching the above criteria.\n"
                + f"\t For example, consider the above case and say you have 3 agents with less than or equal to 2 incidents assigned to them in the chart. You will be creating '3' problems here, one assigned to each agent. \n\n"
            )

        goal, info = super().setup_goal(page=page, config=config)

        if self.level == 2:
            goal = (
                self.short_description
                + f"\n1. Navigate to the Reports > View/Run page. \n"
                + f"\n2. Given the title of the report, search for it on this page. The report shows the number of 'incidents' assigned to an 'agent'.\n"
                + f"\n3. Find the agents with a number of incidents assigned less than or equal to the {self.description_mapping[self.question]} of the number of assigned incidents across agents. For example, if you were asked to find the 'mean' or 'average' for a case where there are 4 agents assigned 1,2,3,2 incidents respectively, the mean would be 2. The list of agents required for solving the following task would be all the agents that have less than or equal to 2 assigned incidents.\n"
                + f"\n4. Navigate to All > Problems. \n"
                + f"\n5. You have to create new 'problems' from this page for all the agents based on the above criteria. Only fill the following fields when creating a new problem:- Impact: '1 - High', Urgency: '1 - High', Problem statement: 'Compulsory training for employee in probation' and 'assign' them to each agent.\n\n"
                + f"Note that you will create as many problems as there are agents matching the above criteria."
                + "\nFor example, consider the above case and say you have 3 agents with less than or equal to 2 incidents assigned to them in the chart. You will be creating '3' problems here, one assigned to each agent. \n"
            )

        return goal, info

    def validate(self, page: Page, chat_messages: list[str]) -> Tuple[float, bool, str, dict]:
        fixed_template_record = {
            "short_description": "Compulsory training for employee in probation",
            "impact": "1",
            "urgency": "1",
        }
        for agent_sysid in self.agent_value_sysids:
            created_problem_response = table_api_call(
                instance=self.instance,
                table="problem",
                params={
                    "sysparm_query": f"assigned_to={agent_sysid}^short_description={self.short_description}",
                },
                method="GET",
            )["result"]
            if len(created_problem_response) == 0:
                return (
                    0,
                    False,
                    "",
                    {
                        "message": f"No problem created for agent {self.agents[agent_sysid]['user_name']}."
                    },
                )
            elif len(created_problem_response) > 1:
                return (
                    0,
                    False,
                    "",
                    {
                        "message": f"Multiple problems created for agent {self.agents[agent_sysid]['user_name']}."
                    },
                )
            created_problem_response = created_problem_response[0]
            for key, value in fixed_template_record.items():
                if str(created_problem_response[key]).lower() != str(value).lower():
                    return (
                        0,
                        False,
                        "",
                        {
                            "message": f"Problem for agent {self.agents[agent_sysid]['user_name']} assigned incorrect value to field {key}."
                        },
                    )
        reward, done, message, info = super().validate(page, chat_messages)
        return reward, done, message, info

    def teardown(self) -> None:
        for agent_sysid in self.agent_sysids:
            created_problem_response = table_api_call(
                instance=self.instance,
                table="problem",
                params={
                    "sysparm_query": f"assigned_to={agent_sysid}",
                },
                method="GET",
            )["result"]
            for problem in created_problem_response:
                db_delete_from_table(
                    instance=self.instance,
                    table="problem",
                    sys_id=problem["sys_id"],
                )
        return super().teardown()

class DashboardRetrieveIncidentAndMinCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="min",
            dashboard_class=SingleChartMinMaxRetrievalTask,
        )

class DashboardRetrieveIncidentAndMeanCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="mean",
            dashboard_class=SingleChartMeanMedianModeRetrievalTask,
        )

class DashboardRetrieveIncidentAndMedianCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="median",
            dashboard_class=SingleChartMeanMedianModeRetrievalTask,
        )

class DashboardRetrieveIncidentAndModeCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="mode",
            dashboard_class=SingleChartMeanMedianModeRetrievalTask,
        )

local_vars = locals().copy()

__TASKS__ = [
    var
    for var in local_vars.values()
    if isinstance(var, type) and issubclass(var, DashDoFinalTask) and var is not DashDoFinalTask
]

DASH_AND_CREATE_PROBLEM = [DashboardRetrieveIncidentAndMinCreateProblemTask]
DASH_COMPUTE_AND_CREATE_PROBLEM = [
    DashboardRetrieveIncidentAndMeanCreateProblemTask,
    DashboardRetrieveIncidentAndMedianCreateProblemTask,
    DashboardRetrieveIncidentAndModeCreateProblemTask,
]


from playwright.sync_api._generated import Page
from typing import Tuple

from .dash_do_base import DashboardRetrieveIncidentAndDoTask, DashDoFinalTask

from ..base import AbstractServiceNowTask
from ..dashboard import SingleChartMinMaxRetrievalTask, SingleChartMeanMedianModeRetrievalTask

from ...api.utils import table_api_call, db_delete_from_table
from ...instance import SNowInstance

from browsergym.workarena.tasks.navigation import AllMenuTask
from browsergym.workarena.tasks.form import CreateProblemTask

class DashboardRetrieveIncidentAndCreateProblemTask(DashboardRetrieveIncidentAndDoTask):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
        question: str = None,
        dashboard_class: AbstractServiceNowTask = None,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question=question,
            dashboard_class=dashboard_class,
        )
        self.attribute_name = "assigned_to"
        self.filter_than = "lesser"
        self.prefix = "DCP"

    def set_compositional_task(self) -> None:
        agent_full_names, agent_value_sysids = self.get_agent_values(
            self.attribute_name, self.filter_than
        )
        self.agent_value_sysids = agent_value_sysids
        create_problem_subtasks = []
        self.short_description = "Compulsory training for employee in probation"
        for agent_full_name in agent_full_names:
            problem_config = {
                "fields": {
                    "short_description": "Problem statement",
                    "urgency": "Urgency",
                    "assigned_to": "Assigned to",
                    "impact": "Impact",
                },
                "task_fields": [
                    "short_description",
                    "urgency",
                    "assigned_to",
                    "impact",
                ],
                "template_record": {
                    "short_description": self.short_description,
                    "impact": "1 - High",
                    "urgency": "1 - High",
                    "assigned_to": agent_full_name,
                },
            }

            create_problem_subtask = [
                # Navigate to the incident list
                AllMenuTask(
                    instance=self.instance,
                    fixed_config={
                        "application": "Problem",
                        "module": "All",
                        "url": "/now/nav/ui/classic/params/target/problem_list.do",
                    },
                    is_validated=False,
                    used_in_level_2=True,
                ),
                # Create a problem
                CreateProblemTask(
                    instance=self.instance,
                    fixed_config=problem_config,
                    is_validated=False,
                    used_in_level_2=True,
                    check_record_created=False,
                ),
            ]
            create_problem_subtasks += create_problem_subtask

        self.compositional_task = create_problem_subtasks

    def setup_goal(self, page: Page) -> tuple[str, dict]:
        self.create_report(
            user_roles=[
                "itil",
                "problem_admin",
                "problem_manager",
                "problem_coordinator",
                "problem_task_analyst",
            ]
        )
        self.set_compositional_task()
        config = self.fixed_config if self.fixed_config else self._get_config()

        if self.level == 3:
            self.task_description = (
                self.task_description
                + f"\t - Please retrieve the '{self.description_mapping[self.question]}' value of the number of incidents assigned across agents. Retrieve agents that have less than or equal number of incidents assigned to them compared to this value.\n"
                + f"\t   For example, if you were asked to find the 'mean' or 'average' for a case where there are 4 agents assigned 1,2,3,2 incidents respectively, the mean would be 2. The list of agents required for solving the following task would be all the agents that have less than or equal to 2 assigned incidents.\n\n"
                + f"\t - Task: For each agent that fits the above criteria, create a 'problem' with the following information (only fill these fields) and assign it to them using the 'Assigned to' field: \n"
                + f"\t\t Impact: '1 - High', Urgency: '1 - High', Problem statement: 'Compulsory training for employee in probation'.\n"
                + f"Note that you will create as many problems as there are agents matching the above criteria.\n"
                + f"\t For example, consider the above case and say you have 3 agents with less than or equal to 2 incidents assigned to them in the chart. You will be creating '3' problems here, one assigned to each agent. \n\n"
            )

        goal, info = super().setup_goal(page=page, config=config)

        if self.level == 2:
            goal = (
                self.short_description
                + f"\n1. Navigate to the Reports > View/Run page. \n"
                + f"\n2. Given the title of the report, search for it on this page. The report shows the number of 'incidents' assigned to an 'agent'.\n"
                + f"\n3. Find the agents with a number of incidents assigned less than or equal to the {self.description_mapping[self.question]} of the number of assigned incidents across agents. For example, if you were asked to find the 'mean' or 'average' for a case where there are 4 agents assigned 1,2,3,2 incidents respectively, the mean would be 2. The list of agents required for solving the following task would be all the agents that have less than or equal to 2 assigned incidents.\n"
                + f"\n4. Navigate to All > Problems. \n"
                + f"\n5. You have to create new 'problems' from this page for all the agents based on the above criteria. Only fill the following fields when creating a new problem:- Impact: '1 - High', Urgency: '1 - High', Problem statement: 'Compulsory training for employee in probation' and 'assign' them to each agent.\n\n"
                + f"Note that you will create as many problems as there are agents matching the above criteria."
                + "\nFor example, consider the above case and say you have 3 agents with less than or equal to 2 incidents assigned to them in the chart. You will be creating '3' problems here, one assigned to each agent. \n"
            )

        return goal, info

    def validate(self, page: Page, chat_messages: list[str]) -> Tuple[float, bool, str, dict]:
        fixed_template_record = {
            "short_description": "Compulsory training for employee in probation",
            "impact": "1",
            "urgency": "1",
        }
        for agent_sysid in self.agent_value_sysids:
            created_problem_response = table_api_call(
                instance=self.instance,
                table="problem",
                params={
                    "sysparm_query": f"assigned_to={agent_sysid}^short_description={self.short_description}",
                },
                method="GET",
            )["result"]
            if len(created_problem_response) == 0:
                return (
                    0,
                    False,
                    "",
                    {
                        "message": f"No problem created for agent {self.agents[agent_sysid]['user_name']}."
                    },
                )
            elif len(created_problem_response) > 1:
                return (
                    0,
                    False,
                    "",
                    {
                        "message": f"Multiple problems created for agent {self.agents[agent_sysid]['user_name']}."
                    },
                )
            created_problem_response = created_problem_response[0]
            for key, value in fixed_template_record.items():
                if str(created_problem_response[key]).lower() != str(value).lower():
                    return (
                        0,
                        False,
                        "",
                        {
                            "message": f"Problem for agent {self.agents[agent_sysid]['user_name']} assigned incorrect value to field {key}."
                        },
                    )
        reward, done, message, info = super().validate(page, chat_messages)
        return reward, done, message, info

    def teardown(self) -> None:
        for agent_sysid in self.agent_sysids:
            created_problem_response = table_api_call(
                instance=self.instance,
                table="problem",
                params={
                    "sysparm_query": f"assigned_to={agent_sysid}",
                },
                method="GET",
            )["result"]
            for problem in created_problem_response:
                db_delete_from_table(
                    instance=self.instance,
                    table="problem",
                    sys_id=problem["sys_id"],
                )
        return super().teardown()

class DashboardRetrieveIncidentAndMinCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"


    def teardown(self) -> None:
        for agent_sysid in self.agent_sysids:
            created_problem_response = table_api_call(
                instance=self.instance,
                table="problem",
                params={
                    "sysparm_query": f"assigned_to={agent_sysid}",
                },
                method="GET",
            )["result"]
            for problem in created_problem_response:
                db_delete_from_table(
                    instance=self.instance,
                    table="problem",
                    sys_id=problem["sys_id"],
                )
        return super().teardown()

class DashboardRetrieveIncidentAndMinCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="min",
            dashboard_class=SingleChartMinMaxRetrievalTask,
        )

class DashboardRetrieveIncidentAndMeanCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"


    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="min",
            dashboard_class=SingleChartMinMaxRetrievalTask,
        )

class DashboardRetrieveIncidentAndMeanCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="mean",
            dashboard_class=SingleChartMeanMedianModeRetrievalTask,
        )

class DashboardRetrieveIncidentAndMedianCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"


    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="mean",
            dashboard_class=SingleChartMeanMedianModeRetrievalTask,
        )

class DashboardRetrieveIncidentAndMedianCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="median",
            dashboard_class=SingleChartMeanMedianModeRetrievalTask,
        )

class DashboardRetrieveIncidentAndModeCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"


    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="median",
            dashboard_class=SingleChartMeanMedianModeRetrievalTask,
        )

class DashboardRetrieveIncidentAndModeCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="mode",
            dashboard_class=SingleChartMeanMedianModeRetrievalTask,
        )

local_vars = locals().copy()

__TASKS__ = [
    var
    for var in local_vars.values()
    if isinstance(var, type) and issubclass(var, DashDoFinalTask) and var is not DashDoFinalTask
]

DASH_AND_CREATE_PROBLEM = [DashboardRetrieveIncidentAndMinCreateProblemTask]
DASH_COMPUTE_AND_CREATE_PROBLEM = [
    DashboardRetrieveIncidentAndMeanCreateProblemTask,
    DashboardRetrieveIncidentAndMedianCreateProblemTask,
    DashboardRetrieveIncidentAndModeCreateProblemTask,
]


        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="median",
            dashboard_class=SingleChartMeanMedianModeRetrievalTask,
        )

class DashboardRetrieveIncidentAndModeCreateProblemTask(
    DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
):
    def __init__(
        self,
        instance: SNowInstance = None,
        seed: int = None,
        fixed_config: list[AbstractServiceNowTask] = None,
        level: int = 2,
    ) -> None:
        """
        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question="mode",
            dashboard_class=SingleChartMeanMedianModeRetrievalTask,
        )

local_vars = locals().copy()

__TASKS__ = [
    var
    for var in local_vars.values()
    if isinstance(var, type) and issubclass(var, DashDoFinalTask) and var is not DashDoFinalTask
]

DASH_AND_CREATE_PROBLEM = [DashboardRetrieveIncidentAndMinCreateProblemTask]
DASH_COMPUTE_AND_CREATE_PROBLEM = [
    DashboardRetrieveIncidentAndMeanCreateProblemTask,
    DashboardRetrieveIncidentAndMedianCreateProblemTask,
    DashboardRetrieveIncidentAndModeCreateProblemTask,
]


        Retrieve the worst performing employee and create a problem to assign them a probation course.
        Attributes:
        -----------
        task_description: str
            The start of the task description to be completed.
        short_description: str
            A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
        """
        super().__init__(
            instance=instance,
            seed=seed,
            fixed_config=fixed_config,
            level=level,
            question=question,
            dashboard_class=dashboard_class,
        )
        self.attribute_name = "assigned_to"
        self.filter_than = "lesser"
        self.prefix = "DCP"

    def set_compositional_task(self) -> None:
        agent_full_names, agent_value_sysids = self.get_agent_values(
            self.attribute_name, self.filter_than
        )
        self.agent_value_sysids = agent_value_sysids
        create_problem_subtasks = []
        self.short_description = "Compulsory training for employee in probation"
        for agent_full_name in agent_full_names:
            problem_config = {
                "fields": {
                    "short_description": "Problem statement",
                    "urgency": "Urgency",
                    "assigned_to": "Assigned to",
                    "impact": "Impact",
                },
                "task_fields": [
                    "short_description",
                    "urgency",
                    "assigned_to",
                    "impact",
                ],
                "template_record": {
                    "short_description": self.short_description,
                    "impact": "1 - High",
                    "urgency": "1 - High",
                    "assigned_to": agent_full_name,
                },
            }

            create_problem_subtask = [
                # Navigate to the incident list
                AllMenuTask(
                    instance=self.instance,
                    fixed_config={
                        "application": "Problem",
                        "module": "All",
                        "url": "/now/nav/ui/classic/params/target/problem_list.do",
                    },
                    is_validated=False,
                    used_in_level_2=True,
                ),
                # Create a problem
                CreateProblemTask(
                    instance=self.instance,
                    fixed_config=problem_config,
                    is_validated=False,
                    used_in_level_2=True,
                    check_record_created=False,
                ),
            ]
            create_problem_subtasks += create_problem_subtask

        self.compositional_task = create_problem_subtasks

    def setup_goal(self, page: Page) -> tuple[str, dict]:
        self.create_report(
            user_roles=[
                "itil",
                "problem_admin",
                "problem_manager",
                "problem_coordinator",
                "problem_task_analyst",
            ]
        )
        self.set_compositional_task()
        config = self.fixed_config if self.fixed_config else self._get_config()

        if self.level == 3:
            self.task_description = (
                self.task_description
                + f"\t - Please retrieve the '{self.description_mapping[self.question]}' value of the number of incidents assigned across agents. Retrieve agents that have less than or equal number of incidents assigned to them compared to this value.\n"
                + f"\t   For example, if you were asked to find the 'mean' or 'average' for a case where there are 4 agents assigned 1,2,3,2 incidents respectively, the mean would be 2. The list of agents required for solving the following task would be all the agents that have less than or equal to 2 assigned incidents.\n\n"
                + f"\t - Task: For each agent that fits the above criteria, create a 'problem' with the following information (only fill these fields) and assign it to them using the 'Assigned to' field: \n"