import boto3
import re
import logging
from typing import Optional, Any

from .distance_ocr import DistanceOCR

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)
logger = logging.getLogger(__name__)


def _detect_text_in_image(client, image_bytes: bytes) -> list[str]:
    """
    Detects and returns text from an image using AWS Rekognition.

    :param client: boto3 Rekognition client (from create_rekognition_client)
    :param image_bytes: Image data as bytes (from get_frame_data)
    :return: List of detected text strings
    """
    # Call Rekognition DetectText API
    response = client.detect_text(Image={"Bytes": image_bytes})

    # Extract detected text
    detected_texts = [
        text["DetectedText"]
        for text in response.get("TextDetections", [])
        if text["Type"] == "LINE"
    ]

    return detected_texts


def _extract_distance(text: str, units: Optional[list[str]] = None) -> float | None:
    """
    Extracts a distance value from a text string.
    Returns a float if a valid distance is found, otherwise None.

    :param text: str, the OCR text line
    :param units: list of valid distance units (default ['m', 'ft'])
    :return: float or None
    """

    text = text.replace("\xa0", " ").strip()
    if units is None:
        units = ["m", "ft"]

    # Build a dynamic regex pattern from units list
    # Example: (\d+(?:[.,]\d+)?)\s*(m|ft)\b
    units_pattern = "|".join(map(re.escape, units))
    pattern = re.compile(rf"(\d+(?:[.,]\d+)?)\s*(?:{units_pattern})\b", re.IGNORECASE)

    match = pattern.search(text)
    if not match:
        return None

    raw_value = match.group(1)

    # Normalize comma to dot and convert to float
    return float(raw_value.replace(",", "."))


class AWSDistanceExtractor(DistanceOCR):
    def __init__(
        self, rekognition_client: Optional[Any] = None, region_name: str = "ap-south-1"
    ):
        self.client = rekognition_client or boto3.client(
            "rekognition", region_name=region_name
        )

    def get_image_distance(
        self, image_path: str, *, units: Optional[list[str]] = None, **kwargs
    ) -> float | None:
        """
        Gets live OCR distance for a specific frame.

        :param image_path: Path to the frame image file
        :param units: list of possible units
        :return: Distance or None
        """
        with open(image_path, "rb") as f:
            frame_data = f.read()
        text_lines = _detect_text_in_image(self.client, frame_data)

        # Try to extract distance from each text line
        for text_line in text_lines:
            distance = _extract_distance(text_line, units=units)
            if distance is not None:
                return distance

        return None

def main() -> None:
    import argparse
    from dotenv import load_dotenv

    load_dotenv()

    parser = argparse.ArgumentParser(description="Extract distance from pipe inspection image using Gemini.")
    parser.add_argument("image", help="Path to the image file")
    args = parser.parse_args()

    extractor = AWSDistanceExtractor()
    result = extractor.get_image_distance(args.image)
    print(result if result is not None else "NONE")


if __name__ == "__main__":
    main()