#!/usr/bin/env python3

import argparse
import os
import subprocess

import pyudev

from gettext import gettext as _


KEYDIR = 'server_key'
USB_LABEL = 'portachiavi'
MOUNT_POINT = '/mnt/portachiavi'


class CopyKey(object):
    def __init__(self):
        self._parse_args()

    def _parse_args(self):
        self.parser = argparse.ArgumentParser(
            description=_(
                "Copy the server keys to a local USB key"
                )
            )
        self.parser.add_argument(
            '-s', '--server',
            default="proxy",
            help=_(
                "The server on which we want to connect to"
                ),
            )
        self.parser.add_argument(
            'device',
            help=_(
                "The device to setup with the key, like /dev/sdxN"
                ),
            )
        self.args = self.parser.parse_args()

    def main(self):
        # We need to work on a partition device
        context = pyudev.Context()
        try:
            device = pyudev.Devices.from_device_file(context, self.args.device)
        except pyudev.DeviceNotFoundByFileError:
            self.parser.error(_(
                "{d} should be a device (e.g. like /dev/sdxN)"
                ).format(d=self.args.device)
                )
        if device.device_type != 'partition':
            self.parser.error(_(
                "{d} should be a partition device (e.g. like /dev/sdxN)"
                ).format(d=self.args.device)
                )

        # Get device informations and warn that all data will be deleted
        print(_(
            "Found a {p_size:.2f} GiBi {p_type} partition with label " +
            "{p_label} on {d_vendor} ({d_model})"
            ).format(
                p_type=device.get('ID_FS_TYPE'),
                p_label=device.get('ID_FS_LABEL'),
                # this is a ugly way to show -1.00 when there is no size
                # data for the device instead of crashing
                p_size=int(
                    device.get('ID_PART_ENTRY_SIZE', '-1048576')
                    ) / 1048576.0,
                d_model=device.get('ID_MODEL'),
                d_vendor=device.get('ID_VENDOR'),
                )
            )
        print(_(
            "We are going to overwrite this partition\n" +
            "this will OVERWRITE ALL DATA\n"
            ))
        input("Press enter to continue, Ctrl-C to cancel.")

        # refs: fuss #582 and debian #907034
        print(_(
            "Attenzione: se i prossimi messaggi sono tradotti solo " +
            "parzialmente in italiano, alla richiesta " +
            "``Proceed anyway? (y,N)`` è necessario rispondere 's' " +
            "anziché 'y'.\n" +
            "Nelle altre lingue le traduzioni sono complete e si possono " +
            "seguire le indicazioni.\n" +
            "Vedi https://work.fuss.bz.it/issues/582"
            ))

        # Format the device and mount it
        try:
            subprocess.check_call([
                'mkfs.ext4',
                '-L',
                USB_LABEL,
                self.args.device
                ])
        except Exception as e:
            self.parser.error(_(
                "Could not format {device}: {e}"
                ).format(
                    device=self.args.device,
                    e=e,
                    ))

        try:
            os.makedirs(MOUNT_POINT, exist_ok=True)
        except Exception as e:
            self.parser.error(_(
                "Could not create directory {dir}: {e}".format(
                    dir=MOUNT_POINT,
                    e=e,
                    )
                ))
        try:
            subprocess.check_call([
                'mount',
                self.args.device,
                MOUNT_POINT
                ])
        except Exception as e:
            self.parser.error(_(
                "Could not mount {device}: {e}"
                ).format(
                    device=self.args.device,
                    e=e,
                    ))

        # Then we need a directory to write the keys into
        keydir_path = os.path.join(MOUNT_POINT, KEYDIR)
        try:
            os.makedirs(keydir_path, exist_ok=True)
        except Exception as e:
            self.parser.error(_(
                "Could not create directory {dir}: {e}\n" +
                "{device} has been left mounted on {path}"
                ).format(
                    dir=keydir_path,
                    e=e,
                    device=self.args.device,
                    path=MOUNT_POINT,
                    )
                )

        # And finally, we try to copy stuff from the server
        try:
            subprocess.check_call([
                'scp',
                '{server}:/etc/fuss-server/client_keys/client-rsa*'.format(
                    server=self.args.server,
                    ),
                keydir_path,
                ])
        except Exception as e:
            self.parser.error(_(
                "Could not copy the key to the usb key: {e}\n" +
                "{device} has been left mounted on {path}"
                ).format(
                    e=e,
                    device=self.args.device,
                    path=MOUNT_POINT,
                    )
                )

        # And umount the device
        try:
            subprocess.check_call([
                'umount',
                MOUNT_POINT
                ])
        except Exception as e:
            self.parser.error(_(
                "Could not umount {mount}: {e}\n" +
                "The key has already been copied to it, so you can " +
                "probably umount the device yourself and use it."
                ).format(
                    mount=MOUNT_POINT,
                    e=e,
                    ))

        print(_(
            (
                "The keys have been successfully copied to {key}, " +
                "you can now disconnect it and use it to connect " +
                "clients to the server"
                ).format(
                    key=self.args.device
                    )
            ))


if __name__ == '__main__':
    CopyKey().main()
