"""ImportFile module."""

from t_nextgen.nextgen_window import NextGenWindow

import contextlib
import _ctypes
from t_nextgen.exceptions import (
    NextGenEdiNotFoundException,
    NextGenControlLostException,
    NextGenDuplicateImportException,
    NextGenImportTimeoutException,
    NextGenPatientPayException,
    PostingSheetTimeOutException,
)
from t_desktop.config import IS_WINDOWS_OS

if IS_WINDOWS_OS:
    from pywinauto.application import WindowSpecification
    from pywinauto.findwindows import ElementNotFoundError
    from pywinauto.keyboard import send_keys
import time
from datetime import datetime, timedelta

from pathlib import Path
from t_nextgen.utils import utility


class ImportFileWindow(NextGenWindow):
    """ImportFile class with methods to interact with import file window."""

    @property
    def window(self) -> WindowSpecification:
        """Get control of Import Window."""
        self.desktop_app.dialog.child_window(title="frmERA", control_type="Window").wait("exists", timeout=10)
        return self.desktop_app.dialog.child_window(title="frmERA", control_type="Window")

    @property
    def report_viewer_window(self) -> WindowSpecification:
        """Return the report_viewer_window window element."""
        return self.desktop_app.dialog.child_window(auto_id="ReportViewer", control_type="Window")

    def click_era_posting_from_processes_menu(self) -> None:
        """Click on the ERA Posting option in the Processes menu."""
        self.logger.debug("Clicking on ERA Posting from Processes Menu.")
        self.desktop_app.click_file_menu_button()
        file_menu = self.desktop_app.get_file_menu()
        self.desktop_app.click_processes_button_in_file_menu(file_menu)
        processes_menu = self.desktop_app.get_processes_menu_from_file_menu(file_menu)
        with contextlib.suppress(_ctypes.COMError):
            processes_menu.child_window(title="ERA Posting...", control_type="MenuItem", found_index=0).click_input()

    def click_cancel_import_window(self) -> None:
        """Click on cancel button in Import Window."""
        self.logger.debug("Clicking on Cancel button in Import Window.")
        with contextlib.suppress(_ctypes.COMError):
            self.window.child_window(title="cmdCancel", auto_id="cmdCancel", control_type="Button").click()

    def select_directory_import(self) -> None:
        """Select the directory import option."""
        self.logger.debug("Selecting Directory Import option.")
        with contextlib.suppress(_ctypes.COMError):
            self.window.child_window(
                title="optFolderSearch", auto_id="optFolderSearch", control_type="RadioButton"
            ).click()

    def set_835_directory_path(self, folder_835_path: str) -> None:
        """Set the path for the 835 directory.

        Args:
            folder_835_path (str): the folder path where 835 files are stored
        """
        self.logger.debug(f"Setting 835 Directory Path: {folder_835_path}")
        with contextlib.suppress(_ctypes.COMError):
            self.window.child_window(title="txtFolderName", auto_id="txtFolderName", control_type="Edit").set_text(
                folder_835_path
            )

    def click_find_button(self) -> None:
        """Click on find button."""
        self.logger.debug("Clicking on Find button.")
        with contextlib.suppress(_ctypes.COMError):
            self.window.child_window(title="cmdFind", auto_id="cmdFind", control_type="Button").click()

    def get_edi_pane(self) -> WindowSpecification:
        """Get EDI Pane control.

        Returns:
            WindowSpecification: EDI Pane Control
        """
        pane = self.window.child_window(auto_id="frmFolderResults", control_type="Group").child_window(
            auto_id="lstListing", control_type="Pane"
        )
        pane.wait("exists", timeout=15)
        return pane

    def get_edi_checkbox_count(self, edi_pane: WindowSpecification) -> int:
        """Get the EDI CheckBox count aka total number of EDIs to be imported.

        Args:
            edi_pane (WindowSpecification): EDI Pane control

        Returns:
            int: number of EDIs found
        """
        check_box_count = len(edi_pane.descendants(control_type="CheckBox"))
        if check_box_count == 0:
            self.desktop_app.dialog.child_window(title="cmdCancel", control_type="Button").click()
            self.logger.debug("No EDI files found in the 835 folder.")
            raise NextGenEdiNotFoundException("No EDI files found in the 835 folder")
        return check_box_count

    def select_edi_row_checkboxes(self, edi_pane: WindowSpecification, check_box_count: int) -> None:
        """Select all the EDIs as visible in ERA processing window in NextGen App.

        Args:
            edi_pane (WindowSpecification): EDI Pane control
            check_box_count (int): number of EDIs (checkboxes) to be selected in sequence
        """
        self.logger.debug(f"Selecting EDI Row Checkboxes. {check_box_count} EDIs found.")
        for i in range(check_box_count):
            send_keys("{DOWN}")
            time.sleep(1)
            with contextlib.suppress(_ctypes.COMError):
                checkbox_index = 6 if i > 6 else i
                edi_pane.child_window(control_type="CheckBox", found_index=checkbox_index).click()

    def import_edi_files(self) -> None:
        """Click on import button in the ERA processing window in NextGen App."""
        self.logger.debug("Clicking on Import button.")
        data = self.window.child_window(title="cmdImport", auto_id="cmdImport", control_type="Button")
        with contextlib.suppress(_ctypes.COMError):
            data.click()
        self.wait_for_edi_import_to_finish()

    def wait_for_edi_import_to_finish(self) -> None:
        """Waits for the EDIs to be imported into the NextGen App."""
        self.logger.debug("Waiting for EDI import to finish.")
        start_time = datetime.now()
        end_time = start_time + timedelta(seconds=3600)
        time.sleep(1)
        max_tries = 7
        current_try = 0
        try:
            if self.patient_has_duplicated_import():
                self.logger.debug("Patient has duplicated import.")
                raise NextGenDuplicateImportException("Current 835 folder has EDI that is already imported")
            elif self.patient_pay_file_modal_exist():
                self.logger.debug(
                    "There are more than 835 files in the folder. Please ensure only 835 files remain in the folder."
                )
                raise NextGenPatientPayException("Remove Patient Pay from the current 835 Folder")
        except RuntimeError:
            raise NextGenControlLostException("Lost control of NextGen Application")

        while self.import_edi_modal_exist() and datetime.now() < end_time:
            if current_try > max_tries:
                raise Exception(
                    "Could not import current payment folder or lost NextGen reference and could not recover"
                )
            try:
                self.app = self.desktop_app.connect_to_logged_in_screen()
                self._process_import_modal()
            except (ElementNotFoundError, TimeoutError):
                current_try += 1
                time.sleep(10)

        if datetime.now() >= end_time:
            raise NextGenImportTimeoutException("Could not import current payment folder within 3600 seconds")

    def _process_import_modal(self) -> None:
        """Handle Import Processing Dialog."""
        modal = self.desktop_app.dialog.child_window(title="NextGen", control_type="Window")
        if modal.exists(timeout=3, retry_interval=1):
            buttons_list = modal.wrapper_object().descendants(control_type="Button")
            if len(buttons_list) == 2 and buttons_list[0].texts()[0] == "OK" and buttons_list[1].texts()[0] == "Close":
                with contextlib.suppress(_ctypes.COMError):
                    modal.child_window(title="OK", auto_id="2", control_type="Button").click()

    def convert_edi_files_to_excel(self, excel_file_path: str) -> None:
        """Converts EDI files to CSV format by interacting with the application's excel export functionality.

        Args:
            excel_file_path (str): The file path where the exported excel should be saved.
        """
        self.logger.debug("Converting EDI files to Excel.")
        self.click_export_to_excel_icon()
        self.set_excel_export_path(excel_file_path)
        self.export_edi_files()
        pathlib_path = Path(rf"{excel_file_path}")
        try:
            utility.wait_until_file_downloads(pathlib_path.parent, pathlib_path.name, wait_time=500)
        except TimeoutError:
            if self.is_export_modal_open():
                self.desktop_app.dialog.child_window(auto_id="Cancel", control_type="Button")
                raise PostingSheetTimeOutException("PostingSheet not created within 500 seconds")

    def is_export_modal_open(self) -> bool:
        """Checks if the export modal dialog is currently open in the NextGen."""
        try:
            with contextlib.suppress(_ctypes.COMError):
                return self.desktop_app.dialog.child_window(auto_id="FileDialog", control_type="Custom").exists(
                    timeout=3, retry_interval=1
                )
        except ElementNotFoundError:
            return False

    def export_edi_files(self) -> None:
        """Click the export button in the window after clicking the excel icon in the NextGen App."""
        self.logger.debug("Exporting EDI files to Excel.")
        with contextlib.suppress(_ctypes.COMError):
            self.report_viewer_window.child_window(title="Export", control_type="Button").click_input()

    def set_excel_export_path(self, export_path: str) -> None:
        """Set csv export path for converted EDIs in the window that pops up after clicking the excel icon.

        Args:
            export_path (str): The path where the generated csv would be stored
        """
        self.logger.debug(f"Setting Excel Export Path: {export_path}")
        closest_window = self.desktop_app.dialog.child_window(
            auto_id="ReportViewer", control_type="Window"
        ).child_window(auto_id="FileDialog", control_type="Custom")
        with contextlib.suppress(_ctypes.COMError):
            closest_window.child_window(control_type="Edit").set_text(export_path)

    def click_export_to_excel_icon(self) -> None:
        """Convert imported EDIs to Excel. Clicks on the Export to Excel icon in the NextGen App."""
        self.logger.debug("Clicking on Export to Excel icon.")
        excel_button = (
            self.desktop_app.dialog.child_window(auto_id="ReportViewer", control_type="Window")
            .child_window(control_type="ToolBar", class_name="ToolBar")
            .child_window(control_type="Button", found_index=7)
        )
        if excel_button.exists(timeout=5):
            with contextlib.suppress(_ctypes.COMError):
                excel_button.click_input()
                self.logger.info("Excel button clicked successfully.")

            closest_window = self.desktop_app.dialog.child_window(
                auto_id="ReportViewer", control_type="Window"
            ).child_window(auto_id="FileDialog", control_type="Custom")
            closest_window.wait("ready", timeout=3)
            self.logger.info("FileDialog window is ready.")
        else:
            self.logger.warning("Excel button not found within timeout.")

    def import_edi_modal_exist(self) -> bool:
        """Look at a reference to a modal on the next screen to see if the import is finished.

        The reference of this template comes from the screen after importation.
        If it finds the screen, it returns False due to negation; if it doesn't find the screen,
        a _ctypes.COMError error is raised, which falls into the exception and returns True to
        maintain waiting for the download.
        """
        with contextlib.suppress((_ctypes.COMError, TimeoutError, RuntimeError)):
            return not self.desktop_app.dialog.child_window(
                title="ERA Import Posting - Enhanced Report Mode", auto_id="ReportViewer", control_type="Window"
            ).exists(timeout=5, retry_interval=1)
            # Return True if a timeouterror or RuntimeError happens to prevent break the import
        return True

    def patient_has_duplicated_import(self) -> bool:
        """This method checks if the patient has duplicated import.

        Args:
            dialog2 (WindowSpecification): dialog2 window
        Returns:
            bool: True if the patient has duplicated import, False otherwise
        """
        with contextlib.suppress(_ctypes.COMError):
            return self.desktop_app.dialog.child_window(
                auto_id="65535",
                control_type="Text",
                title="Some files/checks were identified as duplicate imports.  Continue?",
            ).exists(timeout=3, retry_interval=1)
        return False

    def _handle_duplicate_import(self) -> None:
        """Handle Duplicate Import Dialog.

        Raises:
            NextGenDuplicateImportException: For duplicate import
        """
        nextgen_dialog = self.desktop_app.dialog.child_window(title="NextGen", control_type="Window")
        with contextlib.suppress(_ctypes.COMError):
            nextgen_dialog.child_window(title="No", auto_id="7", control_type="Button").click_input()
            self.window.child_window(title="cmdCancel", control_type="Button").click_input()

    def _handle_patient_pay_exception(self) -> None:
        """Handles Patient Pay Dialog."""
        with contextlib.suppress(_ctypes.COMError):
            self.desktop_app.dialog.child_window(title="Close", control_type="Button", found_index=0).click()
            self.desktop_app.dialog.child_window(title="cmdCancel", control_type="Button").click()

    def patient_pay_file_modal_exist(self) -> bool:
        """This method checks if the Patient Pay file modal exists.

        Returns:
            bool: True if the Patient Pay file modal exists, False otherwise
        """
        with contextlib.suppress(_ctypes.COMError):
            return self.desktop_app.dialog.child_window(
                auto_id="65535",
                control_type="Text",
                title="Please select either ERA files or Patient Pay files but not both.",
            ).exists(timeout=3, retry_interval=1)
        return False
