class AutoBackup(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '1.0.0'
    __license__ = 'GPL3'
    __description__ = 'This plugin backups files when internet is available.'

    def __init__(self):
        self.ready = False
        self.tries = 0
        self.status = StatusFile('/root/.auto_backup')

    def on_loaded(self):
        for opt in ['files', 'interval', 'commands', 'max_tries']:
            if opt not in self.options or (opt in self.options
                                           and self.options[opt] is None):
                logging.error(f"[auto_backup] Option {opt} is not set.")
                return

        self.ready = True
        logging.info("[auto_backup] Successfully loaded.")

    def on_internet_available(self, agent):
        if not self.ready:
            return

        if self.options[
                'max_tries'] and self.tries >= self.options['max_tries']:
            return

        if self.status.newer_then_days(self.options['interval']):
            return

        # Only backup existing files to prevent errors
        existing_files = list(
            filter(lambda f: os.path.exists(f), self.options['files']))
        files_to_backup = " ".join(existing_files)

        try:
            display = agent.view()

            logging.info("[auto_backup] Backing up...")
            display.set('status', 'Backing up...')
            display.update()

            for cmd in self.options['commands']:
                logging.info(
                    f"[auto_backup] Running {cmd.format(files=files_to_backup)}"
                )
                process = subprocess.Popen(cmd.format(files=files_to_backup),
                                           shell=True,
                                           stdin=None,
                                           stdout=open("/dev/null", "w"),
                                           stderr=None,
                                           executable="/bin/bash")
                process.wait()
                if process.returncode > 0:
                    raise OSError(f"Command failed (rc: {process.returncode})")

            logging.info("[auto_backup] Backup done.")
            display.set('status', 'Backup done!')
            display.update()
            self.status.update()
        except OSError as os_e:
            self.tries += 1
            logging.info(f"[auto_backup] Error: {os_e}")
            display.set('status', 'Backup failed!')
            display.update()
class GitBackup(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '1.0.0'
    __license__ = 'GPL3'
    __description__ = 'git_backup'

    def __init__(self):
        self.ready = False
        self.tries = 0
        logging.debug("GIT BACKUP")
        self.status = StatusFile('/root/.git_backup')

    # called when http://<host>:<port>/plugins/<plugin>/ is called
    # must return a html page
    # IMPORTANT: If you use "POST"s, add a csrf-token (via csrf_token() and render_template_string)
    def on_webhook(self, path, request):
        pass

    # called when the plugin is loaded
    def on_loaded(self):
        self.ready = True
        logging.info("GIT-BACKUP: Successfully loaded.")

    # called before the plugin is unloaded
    def on_unload(self, ui):
        pass

    # called hen there's internet connectivity
    def on_internet_available(self, agent):
        if not self.ready:
            return
        if self.tries >= 2:
            return

        if self.status.newer_then_days(self.options['interval']):
            return
        try:
            f = open("/home/pi/git_err.txt", "a+")
            display = agent.view()
            logging.info("GITBACKUP: Backing up ...")
            display.set('status', 'Backing up ...')
            display.update()
            logging.info(f"GIT-BACKUP: Running")
            process = subprocess.Popen([
                'sudo cp -r /root/brain.nn /root/brain.json /root/.api-report.json /root/handshakes/ /root/peers/ /etc/pwnagotchi/ /var/log/pwnagotchi.log /root/Pwnagotchi/ && cd /root/Pwnagotchi/ && sudo git pull && sudo  git add . && sudo  git commit -am "backup" && sudo git push'
            ],
                                       shell=True,
                                       stderr=f,
                                       stdin=f)
            process.wait()
            f.close()
            logging.info("GIT-BACKUP: backup done")
            display.set('status', 'GIT-Backup done!')
            display.update()
            self.status.update()
        except OSError as os_e:
            self.tries += 1
            logging.info(f"GIT-BACKUP: Error: {os_e}")
            display.set('status', 'Backup failed!')
            display.update()

    # called to setup the ui elements
    def on_ui_setup(self, ui):
        pass
        # called when the ui is updated
    def on_ui_update(self, ui):
        pass  # update those elements

    # called when the hardware display setup is done, display is an hardware specific object
    def on_display_setup(self, display):
        pass

    # called when everything is ready and the main loop is about to start
    def on_ready(self, agent):
        logging.info("unit is ready")
        # you can run custom bettercap commands if you want
        #   agent.run('ble.recon on')
        # or set a custom state
        #   agent.set_bored()

    # called when the AI finished loading
    def on_ai_ready(self, agent):
        pass

    # called when the AI finds a new set of parameters
    def on_ai_policy(self, agent, policy):
        pass

    # called when the AI starts training for a given number of epochs
    def on_ai_training_start(self, agent, epochs):
        pass

    # called after the AI completed a training epoch
    def on_ai_training_step(self, agent, _locals, _globals):
        pass

    # called when the AI has done training
    def on_ai_training_end(self, agent):
        pass

    # called when the AI got the best reward so far
    def on_ai_best_reward(self, agent, reward):
        pass

    # called when the AI got the worst reward so far
    def on_ai_worst_reward(self, agent, reward):
        pass

    # called when a non overlapping wifi channel is found to be free
    def on_free_channel(self, agent, channel):
        pass

    # called when the status is set to bored
    def on_bored(self, agent):
        pass

    # called when the status is set to sad
    def on_sad(self, agent):
        pass

    # called when the status is set to excited
    def on_excited(self, agent):
        pass

    # called when the status is set to lonely
    def on_lonely(self, agent):
        pass

    # called when the agent is rebooting the board
    def on_rebooting(self, agent):
        pass

    # called when the agent is waiting for t seconds
    def on_wait(self, agent, t):
        pass

    # called when the agent is sleeping for t seconds
    def on_sleep(self, agent, t):
        pass

    # called when the agent refreshed its access points list
    def on_wifi_update(self, agent, access_points):
        pass

    # called when the agent refreshed an unfiltered access point list
    # this list contains all access points that were detected BEFORE filtering
    def on_unfiltered_ap_list(self, agent, access_points):
        pass

    # called when the agent is sending an association frame
    def on_association(self, agent, access_point):
        pass

    # called when the agent is deauthenticating a client station from an AP
    def on_deauthentication(self, agent, access_point, client_station):
        pass

    # callend when the agent is tuning on a specific channel
    def on_channel_hop(self, agent, channel):
        pass

    # called when a new handshake is captured, access_point and client_station are json objects
    # if the agent could match the BSSIDs to the current list, otherwise they are just the strings of the BSSIDs
    def on_handshake(self, agent, filename, access_point, client_station):
        pass

    # called when an epoch is over (where an epoch is a single loop of the main algorithm)
    def on_epoch(self, agent, epoch, epoch_data):
        pass

    # called when a new peer is detected
    def on_peer_detected(self, agent, peer):
        pass

    # called when a known peer is lost
    def on_peer_lost(self, agent, peer):
        pass