# -*- coding: utf-8 -*-

import os
import re
import time
import random
import mimetypes
import requests
from urllib.parse import urlparse

from config import (
    STORAGE_DIR,
    PUBLIC_BASE_URL,
    MIN_IMAGE_SIZE_BYTES,
)

from PIL import Image


MAX_DOWNLOAD_IMAGES = 15
IMAGE_DOWNLOAD_TIMEOUT = 10
IMAGE_DOWNLOAD_SLEEP_MIN = 0.05
IMAGE_DOWNLOAD_SLEEP_MAX = 0.18


HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/136.0.0.0 Safari/537.36"
    ),
    "Accept": "image/avif,image/webp,image/apng,image/*,*/*;q=0.8",
    "Accept-Language": "ko-KR,ko;q=0.9,en;q=0.8",
    "Referer": "https://new.land.naver.com/",
}


def safe_filename(value):
    value = str(value or "").strip()
    value = re.sub(r"[^0-9a-zA-Z가-힣._-]+", "_", value)
    return value[:120] or "image"


def normalize_url(url):
    url = str(url or "").strip()
    url = url.replace("\\/", "/")
    url = url.replace("\\u0026", "&")
    url = url.replace("&amp;", "&")

    if url.startswith("//"):
        url = "https:" + url

    return url

def extract_first_image_url(value):
    value = normalize_url(value)

    if "," in value:
        value = value.split(",")[0].strip()

    parts = value.split()

    if parts:
        value = parts[0].strip()

    return normalize_url(value)


def normalize_for_duplicate(url):
    url = normalize_url(url)

    if not url:
        return ""

    parsed = urlparse(url)
    return f"{parsed.scheme}://{parsed.netloc}{parsed.path}"


def is_probably_image_url(url):
    url = normalize_url(url)
    lower = url.lower()

    if not lower.startswith("http"):
        return False

    bad_words = [
        "font/",
        ".woff",
        ".woff2",
        ".ttf",
        ".otf",
        ".eot",
        ".css",
        ".js",
        ".html",
        ".svg",
        "favicon",
        "sprite",
        "icon",
        "ico",
        "logo",
        "button",
        "blank",
        "error",
        "icgnb",
        "gnb",
        "opentalk",
        "alarm",
        "mail",
        "financial.pstatic.net/static/images",
        "static/images/pc",
        "apple-touch",
        "manifest",
        "property-web/font",
        "format(",
        "application/json",
        "api/",
        "front-api",
        "adcr",
        "veta",
        "gfp",
        "og_400x400",
        "og_1125x570",
        "map.pstatic.net",
        "nrb/styles",
        "bg.ol",
        "mt=bg",
        "tile",
    ]

    if any(word in lower for word in bad_words):
        return False

    parsed = urlparse(url)
    path = parsed.path.lower()

    image_exts = [".jpg", ".jpeg", ".png", ".webp", ".gif"]

    if any(path.endswith(ext) for ext in image_exts):
        return True

    good_words = [
        "image",
        "photo",
        "thumb",
        "article",
        "landthumb",
        "phinf",
        "pstatic",
    ]

    return any(word in lower for word in good_words)


def guess_ext(url, content_type=""):
    path = urlparse(url).path
    ext = os.path.splitext(path)[1].lower()

    if ext in [".jpg", ".jpeg", ".png", ".webp", ".gif"]:
        return ext

    if content_type:
        guessed = mimetypes.guess_extension(
            content_type.split(";")[0].strip()
        )

        if guessed in [".jpg", ".jpeg", ".png", ".webp", ".gif"]:
            return guessed

    return ".jpg"


def ensure_dir(path):
    os.makedirs(path, exist_ok=True)


def get_article_image_dir(article_no, image_category):
    return os.path.join(
        STORAGE_DIR,
        "realestate",
        str(article_no),
        safe_filename(image_category)
    )


def get_local_public_url(local_path):
    local_path = local_path.replace("\\", "/")
    storage_root = STORAGE_DIR.replace("\\", "/").rstrip("/")

    if not local_path.startswith(storage_root):
        return ""

    rel_path = local_path.replace(storage_root, "").lstrip("/")
    return PUBLIC_BASE_URL.rstrip("/") + "/" + rel_path


def is_allowed_image_content_type(content_type):
    content_type = str(content_type or "").lower()
    return content_type.startswith("image/")


def download_image(
    article_no,
    image_url,
    image_category="building",
    filename_prefix="image",
    index=1
):
    image_url = extract_first_image_url(image_url)

    if not image_url:
        return None

    if not is_probably_image_url(image_url):
        print("[IMAGE SKIP] 이미지 URL 아님:", image_url)
        return None

    save_dir = get_article_image_dir(article_no, image_category)
    ensure_dir(save_dir)

    time.sleep(random.uniform(IMAGE_DOWNLOAD_SLEEP_MIN, IMAGE_DOWNLOAD_SLEEP_MAX))

    res = requests.get(
        image_url,
        headers=HEADERS,
        timeout=IMAGE_DOWNLOAD_TIMEOUT,
        stream=True
    )

    if res.status_code != 200:
        raise Exception(
            f"이미지 다운로드 실패: status={res.status_code}, url={image_url}"
        )

    content_type = res.headers.get("content-type", "")

    if not is_allowed_image_content_type(content_type):
        print("[IMAGE SKIP] content-type 이미지 아님:", content_type, image_url)
        return None

    ext = guess_ext(image_url, content_type)

    filename = f"{safe_filename(filename_prefix)}_{index}{ext}"
    local_path = os.path.join(save_dir, filename)

    with open(local_path, "wb") as f:
        for chunk in res.iter_content(chunk_size=16384):
            if chunk:
                f.write(chunk)

    file_size = os.path.getsize(local_path)

    width = 0
    height = 0

    try:
        with Image.open(local_path) as img:
            width, height = img.size

    except Exception as e:
        print("[IMAGE SIZE ERROR]", str(e))

    if file_size < int(MIN_IMAGE_SIZE_BYTES):
        try:
            os.remove(local_path)
        except Exception:
            pass

        print("[IMAGE SKIP] 이미지 용량 작음:", file_size, image_url)
        return None

    local_public_url = get_local_public_url(local_path)

    print("[IMAGE LOCAL SAVED]", local_path.replace("\\", "/"))
    print("[IMAGE LOCAL PUBLIC URL]", local_public_url)

    return {
        "image_url": image_url,
        "image_category": image_category,
        "file_name": filename,
        "local_path": local_path.replace("\\", "/"),
        "local_public_url": local_public_url,
        "file_size": file_size,
        "content_type": content_type,
        "width": width,
        "height": height,
    }


def sort_images_for_download(images):
    """
    대표/매물/내부/외부 사진을 우선하고,
    지도/아이콘/기타는 뒤로 보냅니다.
    """

    priority = {
        "representative": 0,
        "main": 0,
        "building": 1,
        "inside": 2,
        "outside": 3,
        "view": 4,
        "floorplan": 5,
        "map": 9,
        "etc": 10,
    }

    def score(item):
        category = str(
            item.get("image_category")
            or item.get("image_type")
            or "etc"
        ).lower()

        return priority.get(category, 8)

    return sorted(images or [], key=score)


def prepare_image_items(images, max_images=MAX_DOWNLOAD_IMAGES):
    unique_items = []
    seen = set()

    sorted_images = sort_images_for_download(images)

    for item in sorted_images:
        image_url = extract_first_image_url(item.get("image_url"))

        if not image_url:
            continue

        if not is_probably_image_url(image_url):
            continue

        duplicate_key = normalize_for_duplicate(image_url)

        if not duplicate_key or duplicate_key in seen:
            continue

        seen.add(duplicate_key)

        unique_items.append({
            "image_url": image_url,
            "image_category": item.get("image_category", "building"),
            "filename_prefix": item.get("filename_prefix", "image"),
        })

        if len(unique_items) >= int(max_images):
            break

    return unique_items


def download_images(article_no, images, max_images=MAX_DOWNLOAD_IMAGES):
    results = []

    items = prepare_image_items(
        images=images,
        max_images=max_images,
    )

    print(f"[IMAGE DOWNLOAD TARGET] {len(items)} / original={len(images or [])}")

    for item in items:
        try:
            result = download_image(
                article_no=article_no,
                image_url=item.get("image_url"),
                image_category=item.get("image_category", "building"),
                filename_prefix=item.get("filename_prefix", "image"),
                index=len(results) + 1,
            )

            if result:
                print(
                    "[IMAGE SAVED]",
                    result.get("file_name"),
                    result.get("file_size"),
                    result.get("local_path")
                )

                results.append(result)

        except Exception as e:
            print("[IMAGE DOWNLOAD ERROR]", str(e))

    print(f"[IMAGE DOWNLOAD DONE] saved={len(results)}")

    return results