from collections.abc import Generator
from pathlib import Path

import aiviro
from aiviro.modules.config import YAMLConfig
from aiviro.modules.pdf import create_pdf_robot
from aiviro.modules.powershell import ShellCommands
from aiviro.modules.reader import InvoiceData, InvoiceReader
from docs.code_examples.erp_handler_example import ERPHandler


class MainStoryXX(aiviro.BaseScenario):
    """
    This class inherits from BaseScenario and implements the main logic of the story.
    This class handles a process of parsing attachments from an email and adding this
    data to an ERP system. In the end, all opened windows are closed by a shell command
    and a report is generated and sent to the list of recipients defined in the config file.
    """

    def __init__(self, config: YAMLConfig):
        super().__init__(config)
        self.pdf_robot = create_pdf_robot()

        # name of the robot is set in the config file
        self.r = self.robot(robot_name="rdp_robot")
        self.erp_handler = ERPHandler(
            rdp_robot=self.r, export_folder=self.tmp_folder.unique_folder
        )
        self.invoice_reader = InvoiceReader(self.pdf_robot)
        self.shell_commands = ShellCommands(self.r)
        self.notifier = self.email_notifier()

    def _before_run(self) -> None:
        """
        e.g. wait until robot is connected to the RDP machine
        """
        self.r.wait_until_ready()

    def _after_run(self) -> None:
        """
        e.g. close all opened applications, send a report etc.
        """
        self.shell_commands.close_all_open_windows().execute()
        self.notifier.send_report()

    def _run(self):
        """
        This method handles the main loop of the story
        """
        for parsed_data, pdf_path in self._get_data_from_emails_pdf():
            try:
                self.erp_handler.handle_story_xx(data=parsed_data, pdf_path=pdf_path)
            except Exception as e:
                self.notifier.error(
                    f"An error occurred when processing PDF file {pdf_path} - {e}"
                )
            else:
                self.notifier.successful(
                    f"Data from PDF file {pdf_path} was successfully added to ERP"
                )

    @aiviro.step
    def _get_data_from_emails_pdf(
        self,
    ) -> Generator[tuple[InvoiceData, Path], None, None]:
        """
        All the required parameters for email extractor can be set in the
         .yaml config file , for example:
         - maximum number of emails to be processed by setting variable
           'max_valid_emails'
         - conditions for email attachments by setting variable 'attachment_conditions',
           e.g. if email contains pdf files within its attachments, then each
           attachment is checked if it is a pdf file, otherwise it is skipped
        """
        for _email, attachments in self.email_extractor().extract_all():
            for one_attachment in attachments:
                if one_attachment.suffix != ".pdf":
                    continue
                data = self._parse_file(one_attachment)
                yield data, one_attachment

    @aiviro.step
    def _parse_file(self, one_attachment: Path) -> InvoiceData:
        # set required pdf file as a source for the pdf robot
        self.pdf_robot.parse(one_attachment)
        return self.invoice_reader.parse()
