import io
import cv2
import logging
import numpy as np
import requests
from PIL import Image

logger = logging.getLogger(__name__)

# Настройки API
API_URL = "https://profile.sibcem.ru:8085/SibCemProfile/api/photo-bot/upload/"
API_KEY = "sibcem_bot_2026_a7f3k9m2x8q1w5e4r6t"


def _image_to_cv2(image_bytes: bytes):
    """Конвертирует байты изображения в OpenCV матрицу (поддержка webp)."""
    # Сначала пробуем cv2.imdecode
    nparr = np.frombuffer(image_bytes, np.uint8)
    img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    if img is not None:
        return img
    
    # Если не сработало, пробуем через PIL (для webp и других форматов)
    try:
        pil_img = Image.open(io.BytesIO(image_bytes))
        if pil_img.mode != 'RGB':
            pil_img = pil_img.convert('RGB')
        img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
        return img
    except Exception as e:
        logger.error(f"Не удалось открыть изображение: {e}")
        return None


def get_crop_coordinates(image_bytes: bytes) -> tuple | None:
    """
    Ищет лицо на фото и возвращает координаты квадратного кропа.
    
    Returns:
        (crop_x1, crop_y1, crop_x2, crop_y2) или None если лицо не найдено.
    """
    try:
        img = _image_to_cv2(image_bytes)
        if img is None:
            logger.warning("Не удалось декодировать изображение")
            return None
        
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        
        cascade_path = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
        face_cascade = cv2.CascadeClassifier(cascade_path)
        faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=8, minSize=(50, 50))
        
        if len(faces) == 0:
            logger.warning("Лицо не найдено на фото")
            return None
        
        if len(faces) > 1:
            faces = sorted(faces, key=lambda f: f[2] * f[3], reverse=True)
        
        x, y, w, h = faces[0]
        
        margin = int(w * 0.3)
        y1 = max(0, y - int(margin * 1.5))
        y2 = min(img.shape[0], y + h + margin)
        x1 = max(0, x - margin)
        x2 = min(img.shape[1], x + w + margin)
        
        side = min(x2 - x1, y2 - y1)
        center_x, center_y = (x1 + x2) // 2, (y1 + y2) // 2
        crop_x1 = max(0, center_x - side // 2)
        crop_y1 = max(0, center_y - side // 2)
        crop_x2 = crop_x1 + side
        crop_y2 = crop_y1 + side
        
        logger.info(f"Лицо найдено: ({x},{y},{w},{h}), кроп: ({crop_x1},{crop_y1},{crop_x2},{crop_y2})")
        return (crop_x1, crop_y1, crop_x2, crop_y2)
        
    except Exception as e:
        logger.error(f"Ошибка в get_crop_coordinates: {e}", exc_info=True)
        return None


def _upload_to_api(image_bytes: bytes, user_id: str, coords: tuple) -> dict:
    """
    Отправляет фото и координаты в Django API.
    Возвращает JSON от сервера.
    """
    x1, y1, x2, y2 = coords
    try:
        response = requests.post(
            API_URL,
            headers={"X-API-Key": API_KEY},
            data={
                "user_id": user_id,
                "crop_x1": x1,
                "crop_y1": y1,
                "crop_x2": x2,
                "crop_y2": y2,
            },
            files={
                "image": ("photo.jpg", image_bytes, "image/jpeg")
            },
            timeout=120,
            verify=False
        )
        response.raise_for_status()
        # Логгируем ответ для отладки
        logger.info(f"API response status: {response.status_code}, body[:500]: {response.text[:500]}")
        return response.json()
    except requests.exceptions.RequestException as e:
        logger.error(f"Ошибка API: {e}")
        return {"status": "error", "reason": f"Ошибка сети: {str(e)}"}
    except Exception as e:
        logger.error(f"Ошибка отправки в API: {e}")
        return {"status": "error", "reason": f"Ошибка: {str(e)}"}


def prepare_ad_photo(input_path: str, user_id: str, output_path: str = None, target_size: int = 96) -> dict:
    """
    Отправляет фото на сервер через API.
    output_path и target_size больше не используются (оставлены для обратной совместимости).
    """
    try:
        # 1. Читаем байты
        if isinstance(input_path, bytes):
            image_bytes = input_path
        else:
            with open(input_path, 'rb') as f:
                image_bytes = f.read()

        # 2. Ищем лицо и получаем координаты
        coords = get_crop_coordinates(image_bytes)
        if not coords:
            return {"success": False, "error": "Лицо не найдено! Пожалуйста, сделайте фото анфас при хорошем освещении."}

        # 3. Отправляем в API
        api_result = _upload_to_api(image_bytes, user_id, coords)

        # 4. Возвращаем результат
        if api_result.get("status") == "ok":
            return {
                "success": True,
                "photo_id": api_result.get("photo_id"),
                "verdict": api_result.get("verdict"),
                "message": api_result.get("message"),
            }
        else:
            return {
                "success": False,
                "error": api_result.get("reason", "Неизвестная ошибка API")
            }

    except Exception as e:
        logger.error(f"Ошибка в prepare_ad_photo: {e}", exc_info=True)
        return {"success": False, "error": str(e)}
