import ipaddress # pyrefly: ignore [missing-import] from marshmallow import Schema, fields, validate, ValidationError HEX_COLOR_REGEX = r"^#[0-9A-Fa-f]{6}$" def validate_ip_address(val): try: ipaddress.ip_address(val) except ValueError: raise ValidationError("Invalid IP address format. Must be a valid IPv4 or IPv6 address.") class CreateDeviceSchema(Schema): device_type_id = fields.UUID( required=True, error_messages={"required": "Device type ID is required."} ) name = fields.String( required=True, validate=validate.Length(min=1, max=200), error_messages={"required": "Device name is required."} ) description = fields.String( required=False, allow_none=True ) ip_address = fields.String( required=True, validate=validate_ip_address, error_messages={"required": "IP address is required."} ) port = fields.Integer( required=False, allow_none=True, validate=validate.Range(min=1, max=65535) ) latitude = fields.Float( required=True, validate=validate.Range(min=-90.0, max=90.0), error_messages={"required": "Latitude is required."} ) longitude = fields.Float( required=True, validate=validate.Range(min=-180.0, max=180.0), error_messages={"required": "Longitude is required."} ) color = fields.String( required=True, validate=validate.Regexp(HEX_COLOR_REGEX), error_messages={"required": "Color code (HEX) is required."} ) avatar_url = fields.String( required=False, allow_none=True, validate=validate.Length(max=512) ) is_active = fields.Boolean( required=False, load_default=True ) class UpdateDeviceSchema(Schema): device_type_id = fields.UUID( required=False ) name = fields.String( required=False, validate=validate.Length(min=1, max=200) ) description = fields.String( required=False, allow_none=True ) ip_address = fields.String( required=False, validate=validate_ip_address ) port = fields.Integer( required=False, allow_none=True, validate=validate.Range(min=1, max=65535) ) latitude = fields.Float( required=False, validate=validate.Range(min=-90.0, max=90.0) ) longitude = fields.Float( required=False, validate=validate.Range(min=-180.0, max=180.0) ) color = fields.String( required=False, validate=validate.Regexp(HEX_COLOR_REGEX) ) avatar_url = fields.String( required=False, allow_none=True, validate=validate.Length(max=512) ) is_active = fields.Boolean( required=False )