import os
import boto3
import logging
import json
import traceback
from datetime import datetime
from botocore.config import Config
from botocore.exceptions import BotoCoreError, ClientError
from urllib.parse import urlparse

# Logger
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("ovh_upload")

# 🔐 ENV
ACCESS_KEY_ID       = os.getenv("ACCESS_KEY_ID")
SECRET_ACCESS_KEY   = os.getenv("SECRET_ACCESS_KEY")
STORAGE_BUCKET_NAME = os.getenv("STORAGE_BUCKET_NAME")
OVH_ENDPOINT        = os.getenv("OVH_ENDPOINT", "https://s3.waw.io.cloud.ovh.net")
OVH_PUBLIC_URL      = os.getenv("OVH_PUBLIC_URL")  # opcjonalne (CDN)
REGION              = os.getenv("OVH_CLOUD_REGION_NAME", "waw")

missing = []
if not ACCESS_KEY_ID:       missing.append("ACCESS_KEY_ID")
if not SECRET_ACCESS_KEY:   missing.append("SECRET_ACCESS_KEY")
if not STORAGE_BUCKET_NAME: missing.append("STORAGE_BUCKET_NAME")
if not REGION:              missing.append("OVH_CLOUD_REGION_NAME")
if missing:
    # Avoid emojis/non-ASCII in console logs to prevent encoding errors on Windows
    raise EnvironmentError(f"Missing environment variables: {', '.join(missing)}")

# ⚙️ Boto3 config – retry + path-style + timeouts
config = Config(
    region_name=REGION,
    signature_version="s3v4",
    retries={"max_attempts": 5, "mode": "standard"},
    connect_timeout=5,
    read_timeout=30,
    s3={"addressing_style": "path", "payload_signing_enabled": False},
)

# 🔄 S3 client
try:
    ovh_client = boto3.client(
        "s3",
        aws_access_key_id=ACCESS_KEY_ID,
        aws_secret_access_key=SECRET_ACCESS_KEY,
        endpoint_url=OVH_ENDPOINT,
        region_name=REGION,
        config=config,
    )
    logger.info("OVH S3 client initialized successfully.")
except Exception:
    logger.error("Failed to initialize S3 client:")
    logger.error(traceback.format_exc())
    raise

# 🧭 public URL helper (fallback gdy brak OVH_PUBLIC_URL)
def _public_url_for(key: str) -> str:
    if OVH_PUBLIC_URL:
        return f"{OVH_PUBLIC_URL.rstrip('/')}/{key.lstrip('/')}"
    host = OVH_ENDPOINT.replace("https://", "").replace("http://", "").strip("/")
    return f"https://{STORAGE_BUCKET_NAME}.{host}/{key.lstrip('/')}"

# 📁 generator ścieżek (z kontrolą slasha + dynamiczne rozszerzenie)
def generate_file_path(base_folder: str, object_id, index: int | None = None, ext: str = ".webp") -> str:
    base_folder = (base_folder or "").strip("/")
    today = datetime.today()
    if index is not None:
        return f"{base_folder}/{today.year}/{today.month:02d}/{today.day:02d}/{object_id}/{index}{ext}"
    return f"{base_folder}/{today.year}/{today.month:02d}/{today.day:02d}/{object_id}{ext}"

# ⬆️ Generyczny upload
def upload_to_ovh(file_data: bytes, file_name: str, *, content_type: str = "application/octet-stream",
                  cache_control: str | None = None) -> str | None:
    if not file_data:
        logger.warning(f"No data to upload for file: {file_name}")
        return None
    try:
        logger.info(f"Upload to OVH: {file_name} ({len(file_data)} bytes)")
        extra = {
            "ContentType": content_type,
            "ContentLength": len(file_data),
            "ACL": "public-read",
        }
        if cache_control:
            extra["CacheControl"] = cache_control

        ovh_client.put_object(
            Bucket=STORAGE_BUCKET_NAME,
            Key=file_name,
            Body=file_data,
            **extra,
        )
        url = _public_url_for(file_name)
        logger.info(f"Upload completed: {url}")
        return url

    except ClientError:
        logger.error("OVH error (ClientError):")
        logger.error(traceback.format_exc())
        return None
    except BotoCoreError:
        logger.error("Boto error (BotoCoreError):")
        logger.error(traceback.format_exc())
        return None
    except Exception:
        logger.error("Unexpected error during upload to OVH:")
        logger.error(traceback.format_exc())
        return None

# 👤 Awatar (domyślnie WebP + twardy cache)
def upload_avatar_to_ovh(file_data: bytes, user_id, *, content_type: str = "image/webp", ext: str = ".webp"):
    key = generate_file_path("avatars", user_id, ext=ext)
    return upload_to_ovh(file_data, key, content_type=content_type, cache_control="public, max-age=31536000, immutable")

# 🏠 Zdjęcia ogłoszeń (indexowane)
def upload_advertisement_image_to_ovh(file_data: bytes, advertisement_id, index: int,
                                      *, content_type: str = "image/webp", ext: str = ".webp"):
    key = generate_file_path("advertisements", advertisement_id, index=index, ext=ext)
    return upload_to_ovh(file_data, key, content_type=content_type, cache_control="public, max-age=31536000, immutable")

# 📄 JSON – zwykle bez długiego cache (albo krótki)
def upload_html_json_to_ovh(json_data: dict, object_id, file_name: str):
    payload = json.dumps(json_data, ensure_ascii=False, indent=2, default=str).encode("utf-8")
    try:
        logger.info(f"Upload JSON to OVH: {file_name} ({len(payload)} bytes)")
        ovh_client.put_object(
            Bucket=STORAGE_BUCKET_NAME,
            Key=file_name,
            Body=payload,
            ContentType="application/json; charset=utf-8",
            ContentLength=len(payload),
            ACL="public-read",
            CacheControl="no-cache, max-age=0",
        )
        url = _public_url_for(file_name)
        logger.info(f"Upload completed: {url}")
        return url
    except ClientError:
        logger.error("OVH error (ClientError):")
        logger.error(traceback.format_exc())
        return None
    except Exception:
        logger.error("Unexpected error during JSON upload to OVH:")
        logger.error(traceback.format_exc())
        return None
