"""Plist parser plugin for MacOS TimeMachine plist files."""

import os

import pytz

from dfdatetime import time_elements as dfdatetime_time_elements

from plaso.containers import events
from plaso.lib import dtfabric_helper
from plaso.lib import errors
from plaso.parsers import plist
from plaso.parsers.plist_plugins import interface


class MacOSTimeMachineBackupEventData(events.EventData):
  """MacOS TimeMachine backup event data.

  Attributes:
    backup_alias (str): alias of the backup.
    destination_identifier (str): identifier of the destination volume.
    snapshot_times (list[dfdatetime.DateTimeValues]): dates and times of
        the creation of backup snaphots.
  """

  DATA_TYPE = 'macos:time_machine:backup'

  def __init__(self):
    """Initializes event data."""
    super().__init__(
        data_type=self.DATA_TYPE)
    self.backup_alias = None
    self.destination_identifier = None
    self.snapshot_times = None


class MacOSTimeMachinePlistPlugin(
    interface.PlistPlugin, dtfabric_helper.DtFabricHelper):
  """Plist parser plugin for MacOS TimeMachine plist files.

  Further details about the extracted fields:
    DestinationID:
      remote UUID hard disk where the backup is done.

    BackupAlias:
      structure that contains the extra information from the destinationID.

    SnapshotDates:
      list of the backup dates.
  """

  NAME = 'time_machine'
  DATA_FORMAT = 'MacOS TimeMachine plist file'

  PLIST_PATH_FILTERS = frozenset([
      interface.PlistPathFilter('com.apple.TimeMachine.plist')])

  PLIST_KEYS = frozenset(['Destinations', 'RootVolumeUUID'])

  _DEFINITION_FILE = os.path.join(
      os.path.dirname(__file__), 'time_machine.yaml')

  def __init__(self):
    """Initializes a plist parser plugin."""
    super().__init__()
    self._backup_alias_map = self._GetDataTypeMap('timemachine_backup_alias')

  # pylint: disable=arguments-differ
  def _ParsePlist(self, parser_mediator, match=None, **unused_kwargs):
    """Extracts relevant MacOS TimeMachine entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfVFS.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
    for destination in match.get('Destinations', []):
      backup_alias_string = None
      snapshot_times = []

      backup_alias_data = destination.get('BackupAlias')
      if backup_alias_data:
        try:
          backup_alias = self._ReadStructureFromByteStream(
              backup_alias_data, 0, self._backup_alias_map)
          backup_alias_string = backup_alias.string

        except (ValueError, TypeError, errors.ParseError) as exception:
          parser_mediator.ProduceExtractionWarning(
              f'unable to parse backup alias value with error: {exception!s}')

      for datetime_value in destination.get('SnapshotDates', []):
        # dfDateTime relies on the time zone but since plistlib does not set
        # one.
        datetime_value = datetime_value.replace(tzinfo=pytz.UTC)

        date_time = dfdatetime_time_elements.TimeElementsInMicroseconds()
        date_time.CopyFromDatetime(datetime_value)
        snapshot_times.append(date_time)

      event_data = MacOSTimeMachineBackupEventData()
      event_data.backup_alias = backup_alias_string
      event_data.destination_identifier = destination.get('DestinationID')
      event_data.snapshot_times = snapshot_times or None

      parser_mediator.ProduceEventData(event_data)


plist.PlistParser.RegisterPlugin(MacOSTimeMachinePlistPlugin)
