from pathlib import Path
from math import gcd

from psd_tools import PSDImage
from app.core.logging import setup_logger
from app.core.constants import KEYWORDS

logger = setup_logger(__name__)

def simplify_ratio(width: int, height: int) -> str:
    """ Return simplified ratio. """
    if width == 0 or height == 0:
        return "0:0"
    g = gcd(width, height)
    return f"{width // g}:{height // g}"


def _safe_bbox(layer):
    """Same bbox extraction logic you used in generate_final_image."""
    bbox = getattr(layer, "bbox", None)
    if not bbox:
        return None
    try:
        if isinstance(bbox, (tuple, list)):
            x1, y1, x2, y2 = map(int, bbox)
        else:
            x1, y1, x2, y2 = int(bbox.x1), int(bbox.y1), int(bbox.x2), int(bbox.y2)

        return (x1, y1, x2, y2) if (x2 > x1 and y2 > y1) else None
    except Exception:
        return None


def extract_psd_ratio(psd_path: Path):
    """
    Rule:
    - If exactly 1 design layer -> return that layer's bbox ratio
    - If 2+ design layers -> return PSD canvas ratio
    """

    try:
        psd = PSDImage.open(psd_path)
    except Exception:
        logger.exception("Error opening PSD")
        return "0:0"

    # PSD canvas ratio
    psd_w = getattr(psd, "width", 0)
    psd_h = getattr(psd, "height", 0)
    psd_ratio = simplify_ratio(psd_w, psd_h)

    # Detect design layers exactly like generate_final_image
    design_layers = []
    for layer in psd.descendants():
        try:
            if hasattr(layer, "visible") and not layer.visible:
                continue

            name = (getattr(layer, "name", "") or "").lower()
            kind = getattr(layer, "kind", "")

            if kind == "smartobject" or any(k in name for k in KEYWORDS):
                bbox = _safe_bbox(layer)
                if bbox:
                    design_layers.append((layer, bbox))

        except Exception:
            pass

    if not design_layers:
        # No design layer -> fallback to PSD ratio
        return psd_ratio

    if len(design_layers) > 1:
        # More than 1 layer -> PSD ratio
        return psd_ratio

    # Exactly 1 layer -> return that layer's ratio
    _, bbox = design_layers[0]
    x1, y1, x2, y2 = bbox
    w = x2 - x1
    h = y2 - y1

    return simplify_ratio(w, h)
