"""The UserAssist Windows Registry plugin."""

import codecs
import os

from dfdatetime import filetime as dfdatetime_filetime

from plaso.containers import events
from plaso.helpers.windows import known_folders
from plaso.lib import dtfabric_helper
from plaso.lib import errors
from plaso.parsers import winreg_parser
from plaso.parsers.winreg_plugins import interface


class UserAssistWindowsRegistryEventData(events.EventData):
    """UserAssist Windows Registry event data.

    Attributes:
      application_focus_count (int): application focus count.
      application_focus_duration (int): application focus duration.
      entry_index (int): entry index.
      key_path (str): Windows Registry key path.
      last_execution_time (dfdatetime.DateTimeValues): date and time the application was
          last executed (or run).
      number_of_executions (int): number of executions.
      value_name (str): name of the Windows Registry value.
    """

    DATA_TYPE = "windows:registry:userassist"

    def __init__(self):
        """Initializes event data."""
        super().__init__(data_type=self.DATA_TYPE)
        self.application_focus_count = None
        self.application_focus_duration = None
        self.entry_index = None
        self.key_path = None
        self.last_execution_time = None
        self.number_of_executions = None
        self.value_name = None


class UserAssistWindowsRegistryKeyPathFilter(interface.WindowsRegistryKeyPathFilter):
    """UserAssist Windows Registry key path filter."""

    _KEY_PATH_FORMAT = (
        "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\"
        "Explorer\\UserAssist\\{{{0:s}}}"
    )

    def __init__(self, user_assist_guid):
        """Initializes Windows Registry key filter.

        Args:
          user_assist_guid (str): UserAssist GUID.
        """
        key_path = self._KEY_PATH_FORMAT.format(user_assist_guid)
        super().__init__(key_path)


class UserAssistPlugin(interface.WindowsRegistryPlugin, dtfabric_helper.DtFabricHelper):
    """Plugin that parses an UserAssist key."""

    NAME = "userassist"
    DATA_FORMAT = "User Assist Registry data"

    FILTERS = frozenset(
        [
            UserAssistWindowsRegistryKeyPathFilter(
                "FA99DFC7-6AC2-453A-A5E2-5E2AFF4507BD"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "F4E57C4B-2036-45F0-A9AB-443BCFE33D9F"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "F2A1CB5A-E3CC-4A2E-AF9D-505A7009D442"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "CEBFF5CD-ACE2-4F4F-9178-9926F41749EA"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "CAA59E3C-4792-41A5-9909-6A6A8D32490E"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "B267E3AD-A825-4A09-82B9-EEC22AA3B847"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "A3D53349-6E61-4557-8FC7-0028EDCEEBF6"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "9E04CAB2-CC14-11DF-BB8C-A2F1DED72085"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "75048700-EF1F-11D0-9888-006097DEACF9"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "5E6AB780-7743-11CF-A12B-00AA004AE837"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "0D6D4F41-2994-4BA0-8FEF-620E43CD2812"
            ),
            UserAssistWindowsRegistryKeyPathFilter(
                "BCB48336-4DDD-48FF-BB0B-D3190DACB3E2"
            ),
        ]
    )

    _DEFINITION_FILE = os.path.join(os.path.dirname(__file__), "userassist.yaml")

    def ExtractEvents(self, parser_mediator, registry_key, **kwargs):
        """Extracts events from a Windows Registry key.

        Args:
          parser_mediator (ParserMediator): mediates interactions between parsers
              and other components, such as storage and dfVFS.
          registry_key (dfwinreg.WinRegistryKey): Windows Registry key.
        """
        version_value = registry_key.GetValueByName("Version")
        count_subkey = registry_key.GetSubkeyByName("Count")

        if not version_value:
            parser_mediator.ProduceWarning("missing version value")
            return

        if not version_value.DataIsInteger():
            parser_mediator.ProduceWarning("unsupported version value data type")
            return

        format_version = version_value.GetDataAsObject()
        if format_version not in (3, 5):
            parser_mediator.ProduceWarning(
                f"unsupported format version: {format_version:d}"
            )
            return

        if not count_subkey:
            parser_mediator.ProduceWarning("missing count subkey")
            return

        userassist_entry_index = 0

        for registry_value in count_subkey.GetValues():
            value_name = codecs.decode(registry_value.name, "rot-13")

            if format_version == 5:
                path_segments = value_name.split("\\")

                for segment_index, path_segment in enumerate(path_segments):
                    path = known_folders.WindowsKnownFoldersHelper.GetPath(path_segment)
                    if path:
                        path_segments[segment_index] = path

                value_name = "\\".join(path_segments)
                # Check if we might need to substitute values.
                if "%" in value_name:
                    value_name = parser_mediator.ExpandWindowsPath(value_name)

            if value_name == "UEME_CTLSESSION":
                continue

            if format_version == 3:
                entry_map = self._GetDataTypeMap("user_assist_entry_v3")
                entry_data_size = 16
            elif format_version == 5:
                entry_map = self._GetDataTypeMap("user_assist_entry_v5")
                entry_data_size = 72
            else:
                parser_mediator.ProduceWarning(
                    f"unsupported format version: {format_version:d}"
                )
                continue

            if not registry_value.DataIsBinaryData():
                parser_mediator.ProduceWarning(
                    f"unsupported value data type: {registry_value.data_type_string:s}"
                )
                continue

            value_data_size = len(registry_value.data)
            if entry_data_size != value_data_size:
                parser_mediator.ProduceWarning(
                    f"unsupported value data size: {value_data_size:d}"
                )
                continue

            try:
                user_assist_entry = self._ReadStructureFromByteStream(
                    registry_value.data, 0, entry_map
                )
            except (ValueError, errors.ParseError) as exception:
                parser_mediator.ProduceWarning(
                    f"unable to parse UserAssist entry value with error: {exception!s}"
                )
                continue

            event_data = UserAssistWindowsRegistryEventData()
            event_data.key_path = count_subkey.path
            event_data.number_of_executions = user_assist_entry.number_of_executions
            event_data.value_name = value_name

            if format_version == 3:
                if event_data.number_of_executions > 5:
                    event_data.number_of_executions -= 5

            elif format_version == 5:
                userassist_entry_index += 1

                event_data.application_focus_count = (
                    user_assist_entry.application_focus_count
                )
                event_data.application_focus_duration = (
                    user_assist_entry.application_focus_duration
                )
                event_data.entry_index = userassist_entry_index

            timestamp = user_assist_entry.last_execution_time
            if timestamp:
                event_data.last_execution_time = dfdatetime_filetime.Filetime(
                    timestamp=timestamp
                )

            parser_mediator.ProduceEventData(event_data)


winreg_parser.WinRegistryParser.RegisterPlugin(UserAssistPlugin)
