import sys
import socket
import tarfile
import hashlib

from datetime import datetime, timedelta

from . import UbacBase, logger, logger_check, parse_list


class UbacFs(UbacBase):
    DEST_SUBDIR = 'fs'

    def __init__(self, destination, paths, freshness=24, nb_to_keep=7):
        super(UbacFs, self).__init__(
            destination, freshness=freshness, nb_to_keep=nb_to_keep
        )

        self.paths = paths

    @classmethod
    def from_section(cls, section, remote):
        return cls(
            remote,
            list(parse_list(section['fs_paths'])),
            freshness=int(section['check_since']),
            nb_to_keep=int(section['nb_to_keep']),
        )

    def backup_all(self):
        for path in self.paths:
            try:
                self.single_path(path)
                self.clean(path)
            except KeyboardInterrupt:
                sys.exit(-1)
            except:
                logger.exception('Error backuping fs path %s', path)

    def ressource_from_path(self, path):
        return hashlib.sha1(path.encode()).hexdigest()

    def single_path(self, path):
        logger.info('backuping path %s', path)
        ressource = self.ressource_from_path(path)
        self.destination.mkdir(
            socket.gethostname(), self.DEST_SUBDIR, ressource
        )
        with self.destination.get_writing_stream(
                    socket.gethostname(),
                    self.DEST_SUBDIR,
                    ressource,
                    datetime.utcnow().strftime('%Y%m%d_%H%M%S') + '.tar'
                ) as stdin:
            stream = tarfile.open(mode='w|', fileobj=stdin)
            stream.add(path)
            stream.close()

    def check_all(self):
        result = True
        for path in self.paths:
            try:
                self.check(path)
            except AssertionError as e:
                logger_check.error(*e.args)
                result = False
        return result

    def check(self, path):
        ressource = self.ressource_from_path(path)
        backups = self.destination.list(
            socket.gethostname(), self.DEST_SUBDIR, ressource
        )
        assert backups, 'No backup found for path %s' % (path)
        last = backups[-1]
        last_date = datetime.strptime(last.split('.', 2)[0], '%Y%m%d_%H%M%S')
        last_age = datetime.utcnow() - last_date
        assert last_age < timedelta(hours=self.freshness), (
            'last backup for path %s is %s' % (path, last_age)
        )
        logger.info('Backup of path %s is fresh enough', path)
        return True

    def clean(self, path):
        ressource = self.ressource_from_path(path)
        backups = self.destination.list(
            socket.gethostname(), self.DEST_SUBDIR, ressource
        )
        for to_del in sorted(backups, reverse=True)[self.nb_to_keep:]:
            logger.info(
                'Removing backup %s of %s %s',
                to_del, self.DEST_SUBDIR, path
            )
            self.destination.remove_backup(
                socket.gethostname(), self.DEST_SUBDIR, ressource, to_del
            )
