#!/usr/bin/python3
"""Make, list and restore backups of the router (vpnrouter_backup).

run makes a backup as backup in /etc/vpn-router/vpn-router.json says, whether or not backups are
enabled, and prints its result; vpn-router-backup.service runs it on the schedule of its timer.
list prints the local archives of this host in backup.path, newest first, or with the pbs target
the snapshots of this host on the Proxmox Backup Server. restore puts back a local archive, or
with --pbs a snapshot, such as host/router/2026-10-25T03:00:00Z, after showing what it holds and
asking for yes, which --yes gives; what it replaces is kept in
/var/lib/vpn-router/backup/before-restore. A failure is a message on standard error; the exit
status is 2 for an invalid request and 1 for any other failure. -h or --help shows the options.

  vpn-router-backup run
  vpn-router-backup list
  vpn-router-backup restore [--yes] ARCHIVE
  vpn-router-backup restore [--yes] --pbs SNAPSHOT
"""

import argparse
import os
import sys

sys.path.insert(0, '/usr/lib/vpn-router')

import vpnrouter
import vpnrouter_backup


class Parser(argparse.ArgumentParser):
    """An argument parser whose errors end with status 2."""

    def error(self, message):
        print(f'{self.prog}: {message}; see {self.prog} --help', file=sys.stderr)
        sys.exit(2)


def confirmed(manifest, yes):
    """Whether to restore the backup of the manifest: yes, or the answer yes to the question."""
    print(f'Backup of {manifest.get("host")} made {manifest.get("time")} by vpn-router {manifest.get("version")}:')
    for item in manifest.get('items', []):
        print(f'  {item}')
    if yes:
        return True
    return input('Replace the router state with it? Type yes: ').strip() == 'yes'


def main(argv):
    parser = Parser(prog='vpn-router-backup', description='Make, list and restore backups of the router.')
    commands = parser.add_subparsers(dest='command', required=True, parser_class=Parser)
    commands.add_parser('run', help='make a backup now')
    commands.add_parser('list', help='list the backups of this host')
    restorer = commands.add_parser('restore', help='put a backup back')
    restorer.add_argument('source', metavar='ARCHIVE|SNAPSHOT', help='a local archive, or with --pbs a snapshot')
    restorer.add_argument('--pbs', action='store_true', help='restore a snapshot of the Proxmox Backup Server')
    restorer.add_argument('--yes', action='store_true', help='do not ask before replacing the router state')
    options = parser.parse_args(argv)
    os.umask(0o077)

    try:
        if options.command == 'run':
            record = vpnrouter_backup.run()
            if record['result'] == 'failed':
                print(f'vpn-router-backup: {record["error"]}', file=sys.stderr)
                return 1
            print(f'Backup {record["archive"] or record["snapshot"]} made, {record["size"]} bytes.')
            for name in record['removed']:
                print(f'Removed {name}.')
            if record['cloud']:
                print(f'Cloud copy to {record["cloud"]["remote"]}: {record["cloud"]["error"] or "ok"}.')
            return 0
        cfg = vpnrouter.load_config()
        if options.command == 'list':
            if cfg['backup']['target'] == 'pbs':
                print(vpnrouter_backup.snapshots(cfg), end='')
            else:
                for item in vpnrouter_backup.archives(cfg['backup']['path']):
                    print(f'{item["name"]}  {item["size"]}')
            return 0
        if options.pbs and options.source.startswith('/'):
            print('vpn-router-backup: a snapshot is type/id/time, such as host/router/2026-10-25T03:00:00Z',
                  file=sys.stderr)
            return 2
        saved = vpnrouter_backup.restore(options.source, options.pbs, lambda manifest: confirmed(manifest, options.yes))
    except vpnrouter_backup.Failure as exc:
        print(f'vpn-router-backup: {exc}', file=sys.stderr)
        return 1
    except OSError as exc:
        print(f'vpn-router-backup: {exc}', file=sys.stderr)
        return 1
    if saved is None:
        print('Nothing restored.')
        return 1
    print(f'Restored; what it replaced is in {saved}.')
    return 0


if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))
