"""
Pydantic models for authentication system.
"""

from enum import Enum
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field


class UserRole(str, Enum):
    """User roles in the system."""

    GUEST = "GUEST"
    USER = "USER"
    ADMIN = "ADMIN"
    SUPER_ADMIN = "SUPER_ADMIN"


class LoginRequest(BaseModel):
    """Authentication request."""

    username: str = Field(..., description="Username in Guacamole")
    password: str = Field(..., description="Password in Guacamole")


class LoginResponse(BaseModel):
    """Successful authentication response."""

    access_token: str = Field(..., description="JWT access token")
    token_type: str = Field(default="bearer", description="Token type")
    expires_in: int = Field(..., description="Token lifetime in seconds")
    user_info: Dict[str, Any] = Field(..., description="User information")


class UserInfo(BaseModel):
    """User information."""

    username: str = Field(..., description="Username")
    role: UserRole = Field(..., description="User role")
    permissions: List[str] = Field(
        default_factory=list, description="System permissions"
    )
    full_name: Optional[str] = Field(None, description="Full name")
    email: Optional[str] = Field(None, description="Email address")
    organization: Optional[str] = Field(None, description="Organization")
    organizational_role: Optional[str] = Field(None, description="Job title")


class ConnectionRequest(BaseModel):
    """Connection creation request.

    Requires JWT token in Authorization header: Bearer <token>
    Get token via /auth/login
    """

    hostname: str = Field(..., description="IP address or hostname")
    protocol: str = Field(
        default="rdp", description="Connection protocol (rdp, vnc, ssh)"
    )
    username: Optional[str] = Field(
        None, description="Username for remote machine connection"
    )
    password: Optional[str] = Field(
        None,
        description="Encrypted password for remote machine connection (Base64 AES-256-GCM)",
    )
    port: Optional[int] = Field(
        None, description="Port (default used if not specified)"
    )
    ttl_minutes: Optional[int] = Field(
        default=60, description="Connection lifetime in minutes"
    )

    enable_sftp: Optional[bool] = Field(
        default=True, description="Enable SFTP for SSH (file browser with drag'n'drop)"
    )
    sftp_root_directory: Optional[str] = Field(
        default="/", description="Root directory for SFTP (default: /)"
    )
    sftp_server_alive_interval: Optional[int] = Field(
        default=0, description="SFTP keep-alive interval in seconds (0 = disabled)"
    )


class ConnectionResponse(BaseModel):
    """Connection creation response."""

    connection_id: str = Field(..., description="Created connection ID")
    connection_url: str = Field(..., description="URL to access connection")
    status: str = Field(..., description="Connection status")
    expires_at: str = Field(..., description="Connection expiration time")
    ttl_minutes: int = Field(..., description="TTL in minutes")


class RefreshTokenRequest(BaseModel):
    """Token refresh request."""

    refresh_token: str = Field(..., description="Refresh token")


class LogoutRequest(BaseModel):
    """Logout request."""

    token: str = Field(..., description="Token to revoke")


class PermissionCheckRequest(BaseModel):
    """Permission check request."""

    action: str = Field(..., description="Action to check")
    resource: Optional[str] = Field(None, description="Resource (optional)")


class PermissionCheckResponse(BaseModel):
    """Permission check response."""

    allowed: bool = Field(..., description="Whether action is allowed")
    reason: Optional[str] = Field(None, description="Denial reason (if applicable)")


class SavedMachineCreate(BaseModel):
    """Saved machine create/update request."""

    name: str = Field(..., min_length=1, max_length=255, description="Machine name")
    hostname: str = Field(
        ..., min_length=1, max_length=255, description="IP address or hostname"
    )
    port: int = Field(..., gt=0, lt=65536, description="Connection port")
    protocol: str = Field(
        ..., description="Connection protocol (rdp, ssh, vnc, telnet)"
    )
    os: Optional[str] = Field(
        None,
        max_length=255,
        description="Operating system (e.g., Windows Server 2019, Ubuntu 22.04)",
    )
    description: Optional[str] = Field(None, description="Machine description")
    tags: Optional[List[str]] = Field(
        default_factory=list, description="Tags for grouping"
    )
    is_favorite: bool = Field(default=False, description="Favorite machine")

    class Config:
        json_schema_extra = {
            "example": {
                "name": "Production Web Server",
                "hostname": "192.168.1.100",
                "port": 3389,
                "protocol": "rdp",
                "os": "Windows Server 2019",
                "description": "Main production web server",
                "tags": ["production", "web"],
                "is_favorite": True,
            }
        }


class SavedMachineUpdate(BaseModel):
    """Saved machine partial update request."""

    name: Optional[str] = Field(None, min_length=1, max_length=255)
    hostname: Optional[str] = Field(None, min_length=1, max_length=255)
    port: Optional[int] = Field(None, gt=0, lt=65536)
    protocol: Optional[str] = None
    os: Optional[str] = Field(None, max_length=255, description="Operating system")
    description: Optional[str] = None
    tags: Optional[List[str]] = None
    is_favorite: Optional[bool] = None


class SavedMachineResponse(BaseModel):
    """Saved machine information response."""

    id: str = Field(..., description="Machine UUID")
    user_id: str = Field(..., description="Owner user ID")
    name: str = Field(..., description="Machine name")
    hostname: str = Field(..., description="IP address or hostname")
    port: int = Field(..., description="Connection port")
    protocol: str = Field(..., description="Connection protocol")
    os: Optional[str] = Field(None, description="Operating system")
    description: Optional[str] = Field(None, description="Description")
    tags: List[str] = Field(default_factory=list, description="Tags")
    is_favorite: bool = Field(default=False, description="Favorite")
    created_at: str = Field(..., description="Creation date (ISO 8601)")
    updated_at: str = Field(..., description="Update date (ISO 8601)")
    last_connected_at: Optional[str] = Field(
        None, description="Last connection (ISO 8601)"
    )
    connection_stats: Optional[Dict[str, Any]] = Field(
        None, description="Connection statistics"
    )

    class Config:
        from_attributes = True


class SavedMachineList(BaseModel):
    """Saved machines list."""

    total: int = Field(..., description="Total number of machines")
    machines: List[SavedMachineResponse] = Field(..., description="List of machines")


class ConnectionHistoryCreate(BaseModel):
    """Connection history record creation request."""

    machine_id: str = Field(..., description="Machine UUID")
    success: bool = Field(default=True, description="Successful connection")
    error_message: Optional[str] = Field(None, description="Error message")
    duration_seconds: Optional[int] = Field(
        None, description="Connection duration in seconds"
    )


class ConnectionHistoryResponse(BaseModel):
    """Connection history record information response."""

    id: str = Field(..., description="Record UUID")
    user_id: str = Field(..., description="User ID")
    machine_id: str = Field(..., description="Machine UUID")
    connected_at: str = Field(..., description="Connection time (ISO 8601)")
    disconnected_at: Optional[str] = Field(
        None, description="Disconnection time (ISO 8601)"
    )
    duration_seconds: Optional[int] = Field(None, description="Duration")
    success: bool = Field(..., description="Successful connection")
    error_message: Optional[str] = Field(None, description="Error message")
    client_ip: Optional[str] = Field(None, description="Client IP")

    class Config:
        from_attributes = True


class BulkHealthCheckRequest(BaseModel):
    """Bulk machine availability check request."""

    machine_ids: List[str] = Field(
        ..., min_items=1, max_items=200, description="List of machine IDs to check"
    )
    timeout: int = Field(
        default=5, ge=1, le=30, description="Timeout for each check in seconds"
    )
    check_port: bool = Field(default=True, description="Check connection port")


class BulkHealthCheckResult(BaseModel):
    """Single machine check result."""

    machine_id: str = Field(..., description="Machine ID")
    machine_name: str = Field(..., description="Machine name")
    hostname: str = Field(..., description="Hostname/IP")
    status: str = Field(..., description="success, failed, timeout")
    available: bool = Field(..., description="Machine is available")
    response_time_ms: Optional[int] = Field(
        None, description="Response time in milliseconds"
    )
    error: Optional[str] = Field(None, description="Error message")
    checked_at: str = Field(..., description="Check time (ISO 8601)")


class BulkHealthCheckResponse(BaseModel):
    """Bulk availability check response."""

    total: int = Field(..., description="Total number of machines")
    success: int = Field(..., description="Number of successful checks")
    failed: int = Field(..., description="Number of failed checks")
    available: int = Field(..., description="Number of available machines")
    unavailable: int = Field(..., description="Number of unavailable machines")
    results: List[BulkHealthCheckResult] = Field(..., description="Detailed results")
    execution_time_ms: int = Field(
        ..., description="Total execution time in milliseconds"
    )
    started_at: str = Field(..., description="Start time (ISO 8601)")
    completed_at: str = Field(..., description="Completion time (ISO 8601)")


class SSHCredentials(BaseModel):
    """SSH credentials for machine."""

    username: str = Field(..., min_length=1, max_length=255, description="SSH username")
    password: str = Field(
        ..., min_length=1, description="SSH password (will be encrypted in transit)"
    )


class BulkSSHCommandRequest(BaseModel):
    """Bulk SSH command execution request."""

    machine_ids: List[str] = Field(
        ..., min_items=1, max_items=100, description="List of machine IDs"
    )
    machine_hostnames: Optional[Dict[str, str]] = Field(
        None,
        description="Optional hostname/IP for non-saved machines {machine_id: hostname}",
    )
    command: str = Field(
        ..., min_length=1, max_length=500, description="SSH command to execute"
    )
    credentials_mode: str = Field(
        ..., description="Credentials mode: 'global' (same for all), 'custom' (per-machine)"
    )
    global_credentials: Optional[SSHCredentials] = Field(
        None, description="Shared credentials for all machines (mode 'global')"
    )
    machine_credentials: Optional[Dict[str, SSHCredentials]] = Field(
        None, description="Individual credentials (mode 'custom')"
    )
    timeout: int = Field(
        default=30, ge=5, le=300, description="Command execution timeout (seconds)"
    )


class BulkSSHCommandResult(BaseModel):
    """Single machine SSH command execution result."""

    machine_id: str = Field(..., description="Machine ID")
    machine_name: str = Field(..., description="Machine name")
    hostname: str = Field(..., description="Hostname/IP")
    status: str = Field(..., description="success, failed, timeout, no_credentials")
    exit_code: Optional[int] = Field(None, description="Command exit code")
    stdout: Optional[str] = Field(None, description="Stdout output")
    stderr: Optional[str] = Field(None, description="Stderr output")
    error: Optional[str] = Field(None, description="Error message")
    execution_time_ms: Optional[int] = Field(
        None, description="Execution time in milliseconds"
    )
    executed_at: str = Field(..., description="Execution time (ISO 8601)")


class BulkSSHCommandResponse(BaseModel):
    """Bulk SSH command execution response."""

    total: int = Field(..., description="Total number of machines")
    success: int = Field(..., description="Number of successful executions")
    failed: int = Field(..., description="Number of failed executions")
    results: List[BulkSSHCommandResult] = Field(..., description="Detailed results")
    execution_time_ms: int = Field(
        ..., description="Total execution time in milliseconds"
    )
    command: str = Field(..., description="Executed command")
    started_at: str = Field(..., description="Start time (ISO 8601)")
    completed_at: str = Field(..., description="Completion time (ISO 8601)") 