#!/usr/bin/env python3
"""enrollment_cli.py -- Gallery management CLI for saltybot social.

Usage:
  ros2 run saltybot_social_enrollment enrollment_cli enroll --name "Alice" [--samples 15] [--mode face]
  ros2 run saltybot_social_enrollment enrollment_cli list
  ros2 run saltybot_social_enrollment enrollment_cli delete --id 3
  ros2 run saltybot_social_enrollment enrollment_cli rename --id 2 --name "Bob"
"""

import argparse
import sys

import rclpy
from rclpy.node import Node

from saltybot_social_msgs.srv import (
    EnrollPerson,
    ListPersons,
    DeletePerson,
    UpdatePerson,
)


class EnrollmentCLI(Node):
    def __init__(self):
        super().__init__('enrollment_cli')
        self._enroll_client = self.create_client(
            EnrollPerson, '/social/enroll'
        )
        self._list_client = self.create_client(
            ListPersons, '/social/persons/list'
        )
        self._delete_client = self.create_client(
            DeletePerson, '/social/persons/delete'
        )
        self._update_client = self.create_client(
            UpdatePerson, '/social/persons/update'
        )

    def enroll(self, name: str, n_samples: int = 10, mode: str = 'face'):
        if not self._enroll_client.wait_for_service(timeout_sec=5.0):
            print('ERROR: /social/enroll service not available')
            return False

        req = EnrollPerson.Request()
        req.name = name
        req.mode = mode
        req.n_samples = n_samples

        print(f'Enrolling "{name}" ({mode}, {n_samples} samples)...')
        future = self._enroll_client.call_async(req)
        rclpy.spin_until_future_complete(self, future, timeout_sec=60.0)

        if future.result() is None:
            print('ERROR: Enrollment timed out')
            return False

        resp = future.result()
        if resp.success:
            print(f'OK: Enrolled "{name}" as person_id={resp.person_id}')
        else:
            print(f'FAILED: {resp.message}')
        return resp.success

    def list_persons(self):
        if not self._list_client.wait_for_service(timeout_sec=5.0):
            print('ERROR: /social/persons/list service not available')
            return

        req = ListPersons.Request()
        future = self._list_client.call_async(req)
        rclpy.spin_until_future_complete(self, future, timeout_sec=10.0)

        if future.result() is None:
            print('ERROR: List request timed out')
            return

        resp = future.result()
        if not resp.persons:
            print('Gallery is empty.')
            return

        print(f'{"ID":>4}  {"Name":<20}  {"Samples":>7}  {"Embedding Dim":>13}')
        print('-' * 50)
        for p in resp.persons:
            dim = len(p.embedding) if p.embedding else 0
            print(f'{p.person_id:>4}  {p.person_name:<20}  {p.sample_count:>7}  {dim:>13}')

    def delete(self, person_id: int):
        if not self._delete_client.wait_for_service(timeout_sec=5.0):
            print('ERROR: /social/persons/delete service not available')
            return False

        req = DeletePerson.Request()
        req.person_id = person_id

        future = self._delete_client.call_async(req)
        rclpy.spin_until_future_complete(self, future, timeout_sec=10.0)

        if future.result() is None:
            print('ERROR: Delete request timed out')
            return False

        resp = future.result()
        if resp.success:
            print(f'OK: {resp.message}')
        else:
            print(f'FAILED: {resp.message}')
        return resp.success

    def rename(self, person_id: int, new_name: str):
        if not self._update_client.wait_for_service(timeout_sec=5.0):
            print('ERROR: /social/persons/update service not available')
            return False

        req = UpdatePerson.Request()
        req.person_id = person_id
        req.new_name = new_name

        future = self._update_client.call_async(req)
        rclpy.spin_until_future_complete(self, future, timeout_sec=10.0)

        if future.result() is None:
            print('ERROR: Rename request timed out')
            return False

        resp = future.result()
        if resp.success:
            print(f'OK: {resp.message}')
        else:
            print(f'FAILED: {resp.message}')
        return resp.success


def main(args=None):
    parser = argparse.ArgumentParser(
        description='saltybot person enrollment CLI'
    )
    subparsers = parser.add_subparsers(dest='command', required=True)

    # enroll
    enroll_p = subparsers.add_parser('enroll', help='Enroll a new person')
    enroll_p.add_argument('--name', required=True, help='Person name')
    enroll_p.add_argument('--samples', type=int, default=10,
                          help='Number of face samples (default: 10)')
    enroll_p.add_argument('--mode', default='face',
                          help='Enrollment mode (default: face)')

    # list
    subparsers.add_parser('list', help='List enrolled persons')

    # delete
    delete_p = subparsers.add_parser('delete', help='Delete a person')
    delete_p.add_argument('--id', type=int, required=True,
                          help='Person ID to delete')

    # rename
    rename_p = subparsers.add_parser('rename', help='Rename a person')
    rename_p.add_argument('--id', type=int, required=True,
                          help='Person ID to rename')
    rename_p.add_argument('--name', required=True, help='New name')

    parsed = parser.parse_args(sys.argv[1:])

    rclpy.init()
    cli = EnrollmentCLI()

    try:
        if parsed.command == 'enroll':
            cli.enroll(parsed.name, parsed.samples, parsed.mode)
        elif parsed.command == 'list':
            cli.list_persons()
        elif parsed.command == 'delete':
            cli.delete(parsed.id)
        elif parsed.command == 'rename':
            cli.rename(parsed.id, parsed.name)
    finally:
        cli.destroy_node()
        rclpy.try_shutdown()


if __name__ == '__main__':
    main()
