import logging
import os
from dataclasses import dataclass
from pathlib import Path
from functools import lru_cache

import boto3
from dotenv import load_dotenv


PROJECT_ROOT = Path(__file__).resolve().parents[1]
DOTENV_PATH = PROJECT_ROOT / ".env"
load_dotenv(dotenv_path=DOTENV_PATH, override=True)

logger = logging.getLogger(__name__)


@dataclass(frozen=True)
class AWSSettings:
    access_key_id: str
    secret_access_key: str
    region: str
    s3_bucket: str
    collection_id: str


class AWSConfig:
    """Central AWS configuration shared across the project."""

    @classmethod
    def get_access_key_id(cls):
        return cls._clean_env("AWS_ACCESS_KEY_ID")

    @classmethod
    def get_secret_access_key(cls):
        return cls._clean_env("AWS_SECRET_ACCESS_KEY")

    @classmethod
    def get_region(cls):
        return cls._clean_env("AWS_REGION") or cls._clean_env("AWS_DEFAULT_REGION") or "us-east-1"

    @classmethod
    def get_s3_bucket(cls):
        return cls._clean_env("S3_BUCKET") or cls._clean_env("AWS_S3_BUCKET")

    @classmethod
    def get_rekognition_collection_id(cls):
        return cls._clean_env("COLLECTION_ID") or cls._clean_env("REKOGNITION_COLLECTION_ID")

    @staticmethod
    def _clean_env(name):
        value = os.getenv(name)
        if value is None:
            return None
        value = value.strip()
        return value or None

    @classmethod
    def validate(cls) -> None:
        required_values = {
            "AWS_ACCESS_KEY_ID": cls.get_access_key_id(),
            "AWS_SECRET_ACCESS_KEY": cls.get_secret_access_key(),
            "AWS_REGION": cls.get_region(),
            "S3_BUCKET": cls.get_s3_bucket(),
            "COLLECTION_ID": cls.get_rekognition_collection_id(),
        }
        missing = [name for name, value in required_values.items() if not value]
        if missing:
            raise ValueError(
                "Missing AWS environment variables: " + ", ".join(sorted(missing))
            )


@lru_cache(maxsize=1)
def get_aws_settings():
    """Return validated AWS settings from environment variables."""
    AWSConfig.validate()
    settings = AWSSettings(
        access_key_id=AWSConfig.get_access_key_id(),
        secret_access_key=AWSConfig.get_secret_access_key(),
        region=AWSConfig.get_region(),
        s3_bucket=AWSConfig.get_s3_bucket(),
        collection_id=AWSConfig.get_rekognition_collection_id(),
    )
    masked_access_key = (
        f"{settings.access_key_id[:4]}...{settings.access_key_id[-4:]}"
        if settings.access_key_id
        else "missing"
    )
    logger.info(
        "AWS settings loaded region=%s bucket=%s collection=%s access_key=%s",
        settings.region,
        settings.s3_bucket,
        settings.collection_id,
        masked_access_key,
    )
    return settings


@lru_cache(maxsize=1)
def get_boto3_session():
    """Create a single boto3 session for the application process."""
    settings = get_aws_settings()
    return boto3.session.Session(
        aws_access_key_id=settings.access_key_id,
        aws_secret_access_key=settings.secret_access_key,
        region_name=settings.region,
    )


@lru_cache(maxsize=1)
def get_s3_client():
    """Return a shared S3 client."""
    return get_boto3_session().client("s3")


@lru_cache(maxsize=1)
def get_rekognition_client():
    """Return a shared Rekognition client."""
    return get_boto3_session().client("rekognition")
