# -*- coding: utf-8 -*-
"""
Poly1305 认证器

Poly1305 消息认证码（MAC）认证器。
"""

from cryptography.hazmat.primitives.poly1305 import Poly1305
from typing import Optional


class Poly1305Authenticator:
    """
    Poly1305 认证器
    
    Poly1305 消息认证码（MAC），用于验证数据的完整性和真实性。
    
    常量:
        KEY_SIZE: 密钥大小（32 字节）
        TAG_SIZE: 标签大小（16 字节）
    """

    KEY_SIZE: int = 32
    TAG_SIZE: int = 16

    def __init__(self, key: Optional[bytes] = None) -> None:
        """
        初始化 Poly1305 认证器
        
        Args:
            key: 32 字节的密钥，None 表示不初始化密钥
        
        Raises:
            ValueError: 密钥长度错误
        """
        if key is not None and len(key) != self.KEY_SIZE:
            raise ValueError(f"密钥长度必须为 {self.KEY_SIZE} 字节，当前: {len(key)}")

        self._key: Optional[bytes] = key
        self._poly1305: Optional[Poly1305] = None

    def set_key(self, key: bytes) -> None:
        """
        设置密钥
        
        Args:
            key: 32 字节的密钥
        
        Raises:
            ValueError: 密钥长度错误
        """
        if len(key) != self.KEY_SIZE:
            raise ValueError(f"密钥长度必须为 {self.KEY_SIZE} 字节，当前: {len(key)}")

        self._key = key
        self._poly1305 = None

    def _get_poly1305(self) -> Poly1305:
        """
        获取 Poly1305 实例
        
        Returns:
            Poly1305: Poly1305 实例
        
        Raises:
            ValueError: 密钥未设置
        """
        if self._key is None:
            raise ValueError("密钥未设置")

        if self._poly1305 is None:
            self._poly1305 = Poly1305(self._key)

        return self._poly1305

    def update(self, data: bytes) -> None:
        """
        更新认证数据
        
        Args:
            data: 要认证的数据
        
        Raises:
            ValueError: 更新失败
        """
        try:
            poly1305 = self._get_poly1305()
            poly1305.update(data)
        except Exception as e:
            raise ValueError(f"更新失败: {e}") from e

    def finalize(self) -> bytes:
        """
        完成认证并获取标签
        
        Returns:
            bytes: 16 字节的标签
        
        Raises:
            ValueError: 认证失败
        """
        try:
            poly1305 = self._get_poly1305()
            tag = poly1305.finalize()
            self._poly1305 = None
            return tag
        except Exception as e:
            raise ValueError(f"认证失败: {e}") from e

    def authenticate(self, data: bytes) -> bytes:
        """
        认证数据并返回标签
        
        Args:
            data: 要认证的数据
        
        Returns:
            bytes: 16 字节的标签
        
        Raises:
            ValueError: 认证失败
        """
        self.update(data)
        return self.finalize()

    def reset(self) -> None:
        """
        重置认证器
        """
        self._poly1305 = None
