"""
USPS Address Data Models
"""

from dataclasses import dataclass
from typing import Optional


@dataclass
class USPSAddress:
    """
    Normalized USPS address with separate components.

    Attributes:
        line1: Primary delivery address (street number + name + suffix)
        line2: Secondary address (apartment, suite, floor) - empty string if not present
        city: City name in ALL CAPS
        state: Two-letter state code in ALL CAPS
        zip_code: ZIP code (5 or 9 digits)
    """
    line1: str
    line2: str
    city: str
    state: str
    zip_code: str

    @property
    def city_state_zip(self) -> str:
        """
        Combined city, state, and ZIP in USPS format.

        Returns:
            String in format "CITY, ST ZIP"
        """
        return f"{self.city}, {self.state} {self.zip_code}"

    @property
    def full_address(self) -> str:
        """
        Complete address with all lines joined by newlines.

        Returns:
            Multi-line address string. Line2 is omitted if empty.
        """
        lines = [self.line1]
        if self.line2:
            lines.append(self.line2)
        lines.append(self.city_state_zip)
        return '\n'.join(lines)

    def as_dict(self) -> dict:
        """
        Convert to dictionary representation.

        Returns:
            Dictionary with all address components including computed properties.
        """
        return {
            'line1': self.line1,
            'line2': self.line2,
            'city': self.city,
            'state': self.state,
            'zip_code': self.zip_code,
            'city_state_zip': self.city_state_zip,
            'full_address': self.full_address,
        }

    def __str__(self) -> str:
        """String representation returns full address."""
        return self.full_address

    def __repr__(self) -> str:
        """Developer-friendly representation."""
        return (f"USPSAddress(line1='{self.line1}', line2='{self.line2}', "
                f"city='{self.city}', state='{self.state}', zip_code='{self.zip_code}')")
