"""
SimpleClient - Example client application for the Hydra Router system.

This module provides a simple interactive client that connects to a HydraRouter
and sends square calculation requests. It demonstrates basic usage of the MQClient
library for client applications.
"""

import asyncio
import sys
import time
from typing import Optional

from .logging_config import setup_logging
from .mq_client import MessageType, MQClient, ZMQMessage
from .router_constants import RouterConstants


class SimpleClient:
    """Simple interactive client for square calculation requests."""

    def __init__(
        self,
        router_address: str = "tcp://localhost:5556",
        client_id: Optional[str] = None,
    ):
        """Initialize the simple client.

        Args:
            router_address: Address of the HydraRouter
            client_id: Unique client identifier (auto-generated if None)
        """
        self.router_address = router_address
        self.client_id = client_id or f"simple-client-{int(time.time())}"
        self.client = MQClient(
            router_address=router_address,
            client_type=RouterConstants.SIMPLE_CLIENT,
            client_id=self.client_id,
        )
        self.running = False
        self.logger = setup_logging(__name__)

    async def start(self) -> None:
        """Start the client and connect to router."""
        try:
            await self.client.connect()
            self.running = True
            self.logger.info(
                f"Simple client {self.client_id} connected to {self.router_address}"
            )
            print(f"✅ Connected to router at {self.router_address}")
            print(f"Client ID: {self.client_id}")

            # Register response handler
            self.client.register_message_handler(
                MessageType.SQUARE_RESPONSE, self._handle_square_response
            )

        except Exception as e:
            self.logger.error(f"Failed to connect to router: {e}")
            print(f"❌ Failed to connect to router: {e}")
            raise

    async def stop(self) -> None:
        """Stop the client and disconnect from router."""
        self.running = False
        if self.client.connected:
            await self.client.disconnect()
            self.logger.info(f"Simple client {self.client_id} disconnected")
            print("👋 Disconnected from router")

    async def send_square_request(self, number: int) -> None:
        """Send a square calculation request.

        Args:
            number: Integer to calculate square of
        """
        if not self.running:
            print("❌ Client not connected")
            return

        try:
            request_id = f"req-{int(time.time() * 1000)}"
            message = ZMQMessage(
                message_type=MessageType.SQUARE_REQUEST,
                timestamp=time.time(),
                client_id=self.client_id,
                request_id=request_id,
                data={"number": number},
            )

            await self.client.send_message(message)
            self.logger.info(
                f"Sent square request for {number} (request_id: {request_id})"
            )
            print(f"📤 Sent request: {number}² = ?")

        except Exception as e:
            self.logger.error(f"Failed to send square request: {e}")
            print(f"❌ Failed to send request: {e}")

    def _handle_square_response(self, message: ZMQMessage) -> None:
        """Handle square calculation response.

        Args:
            message: Response message from server
        """
        try:
            data = message.data or {}
            number = data.get("number")
            result = data.get("result")

            if number is not None and result is not None:
                print(f"📥 Response: {number}² = {result}")
                self.logger.info(f"Received square response: {number}² = {result}")
            else:
                print(f"📥 Response: {data}")
                self.logger.warning(f"Unexpected response format: {data}")

        except Exception as e:
            self.logger.error(f"Error handling square response: {e}")
            print(f"❌ Error processing response: {e}")

    async def run_interactive(self) -> None:
        """Run interactive client session."""
        print("\n🔢 Simple Square Calculator Client")
        print("=" * 40)
        print("Enter integers to calculate their squares")
        print("Commands: 'quit' or 'exit' to stop, 'help' for help")
        print()

        while self.running:
            try:
                # Get user input
                user_input = input("Enter number (or command): ").strip()

                if user_input.lower() in ["quit", "exit", "q"]:
                    break
                elif user_input.lower() in ["help", "h"]:
                    self._show_help()
                    continue
                elif user_input == "":
                    continue

                # Try to parse as integer
                try:
                    number = int(user_input)
                    await self.send_square_request(number)
                except ValueError:
                    print(f"❌ Invalid input: '{user_input}' is not an integer")

            except KeyboardInterrupt:
                print("\n🛑 Interrupted by user")
                break
            except EOFError:
                print("\n🛑 End of input")
                break
            except Exception as e:
                self.logger.error(f"Error in interactive loop: {e}")
                print(f"❌ Error: {e}")

        await self.stop()

    def _show_help(self) -> None:
        """Show help information."""
        print("\n📖 Help:")
        print("  - Enter any integer to calculate its square")
        print("  - 'quit' or 'exit' - Exit the client")
        print("  - 'help' - Show this help message")
        print(f"  - Client ID: {self.client_id}")
        print(f"  - Router: {self.router_address}")
        print()


async def main() -> None:
    """Main entry point for the hydra-client-simple command."""
    import argparse

    parser = argparse.ArgumentParser(
        description="Simple HydraRouter client for square calculations"
    )
    parser.add_argument(
        "--router-address",
        default="tcp://localhost:5556",
        help="Address of the HydraRouter (default: tcp://localhost:5556)",
    )
    parser.add_argument(
        "--client-id", help="Unique client identifier (auto-generated if not provided)"
    )
    parser.add_argument(
        "--number", type=int, help="Send single square request and exit"
    )
    parser.add_argument(
        "--log-level",
        choices=["DEBUG", "INFO", "WARNING", "ERROR"],
        default="INFO",
        help="Logging level (default: INFO)",
    )

    args = parser.parse_args()

    # Setup logging
    setup_logging(__name__, level=args.log_level)

    # Create and start client
    client = SimpleClient(router_address=args.router_address, client_id=args.client_id)

    try:
        await client.start()

        if args.number is not None:
            # Single request mode
            await client.send_square_request(args.number)
            # Wait a moment for response
            await asyncio.sleep(1)
        else:
            # Interactive mode
            await client.run_interactive()

    except KeyboardInterrupt:
        print("\n🛑 Interrupted by user")
    except Exception as e:
        print(f"❌ Error: {e}")
        sys.exit(1)
    finally:
        await client.stop()


def sync_main() -> None:
    """Synchronous wrapper for main function."""
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\n🛑 Interrupted")
    except Exception as e:
        print(f"❌ Error: {e}")
        sys.exit(1)


if __name__ == "__main__":
    sync_main()
