#!/usr/bin/env python3
# zarahome_product_links.py
# — извлекает данные напрямую со страниц товаров Zara Home —
# Формат колонок совпадает с вашим категорийным парсером.

import json, re, sys, time, pathlib, requests, pandas as pd
from bs4 import BeautifulSoup

# ── константы ────────────────────────────────────────────────────
HEADERS   = {"User-Agent": "Mozilla/5.0"}
PID_RE    = re.compile(r"-l(\d+)(?:[/?]|$)")        # productId из URL
REST_API  = ("https://www.zarahome.com/itxrest/3/catalog/store/"
             "85009924/80290000/productsArray?languageId=-1"
             "&productIds={ids}&appId=1")
BRAND = "ZARAHOME"

# ── helpers ──────────────────────────────────────────────────────
def fetch(url: str, json_flag=False):
    """GET-обёртка c timeout и user-agent."""
    r = requests.get(url, headers=HEADERS, timeout=15)
    r.raise_for_status()
    return r.json() if json_flag else r.text

def try_json_ld(soup: BeautifulSoup):
    """Ищем <script type='application/ld+json'> с Product."""
    for tag in soup.find_all("script", attrs={"type": lambda t: t and "ld+json" in t}):
        try:
            data = json.loads(tag.string)
        except Exception:
            continue
        if isinstance(data, list):
            data = next((d for d in data if d.get("@type") == "Product"), None)
        if data and data.get("@type") == "Product":
            offers = data.get("offers", {})
            return {
                # минимальный набор, которого хватит для таблицы
                "name": data.get("name",""),
                "longDescription": data.get("description",""),
                "displayReference": data.get("sku") or data.get("gtin13",""),
                "price": float(offers.get("price",0))*100,
                "weight": "",
                "colors": [],
                "xmedia": [],
                "xmediaDefaultSet": None,
                "image": data.get("image", []),
                "care": [],
                "traceability": {},
                "compositionDetail": {}
            }
    return None

def try_server_state(soup: BeautifulSoup):
    """Пробуем detail из #serverApp-state."""
    tag = soup.select_one("#serverApp-state")
    if not tag:
        return None
    state = json.loads(tag.string)
    for k, v in state.items():
        if "/detail" in k and isinstance(v, dict):
            return v
    prod = state.get("inditex-data", {}).get("product")
    return prod if isinstance(prod, dict) else None

def try_rest_api(url: str):
    """REST /productsArray по productId."""
    m = PID_RE.search(url)
    if not m:
        return None
    pid = m.group(1)
    api_json = fetch(REST_API.format(ids=pid), json_flag=True)
    for p in api_json.get("products", []):
        if p.get("detail"):
            return p["detail"]
        bs = p.get("bundleProductSummaries")
        if bs and bs[0].get("detail"):
            return bs[0]["detail"]
    return None

def get_detail(url: str):
    """Возвращает словарь detail (или бросает ValueError)."""
    soup = BeautifulSoup(fetch(url), "html.parser")
    return (
        try_json_ld(soup)  or
        try_server_state(soup) or
        try_rest_api(url)
    ) or (_ for _ in ()).throw(ValueError("detail не найден"))

def join_imgs(paths):
    return "\n".join(paths)

def rows_from_detail(det: dict, url: str):
    """Собирает все строки CSV-формата из detail."""
    # --- общие картинки ---
    all_imgs = det.get("image", [])
    if det.get("xmedia"):
        media_sets = det["xmedia"]
        if isinstance(media_sets, dict):
            media_sets = [media_sets]
        all_imgs = [f"https://static.zarahome.net/8/photos4{loc['path']}/{m['idMedia']}2.jpg"
                    for loc in media_sets
                    for m   in loc["xmediaItems"][0]["medias"]]
    all_imgs_s = join_imgs(all_imgs)

    # --- текстовые поля ---
    comp_txt = ""
    cdet = det.get("compositionDetail", {})
    if cdet.get("parts"):
        comp_txt = "\n".join(
            f"{p['name']}: " + ", ".join(f"{c['percentage']}% {c['name']}"
            for c in p["composition"])
            for p in cdet["parts"]
        )
    care_txt = "\n".join(c.get("description","") for c in det.get("care", []))
    trace_txt = ""
    if det.get("traceability"):
        trace_txt = "\n".join(
            f"{v['name']}\n" + "\n".join(v["country"])
            for v in det["traceability"].values()
            if isinstance(v, dict) and v.get("country") and v.get("name")
        )

    # --- цветов нет → одна строка ---
    return [[
        url,
        det.get("displayReference",""),
        det.get("name",""),
        "", "",                          # SKU / PartNumber
        det.get("longDescription",""),
        all_imgs[0] if all_imgs else "",
        "", "",                          # Color / Size
        det.get("price",0)/100,
        det.get("weight",""),
        "",
        all_imgs_s,
        all_imgs_s,
        comp_txt,
        care_txt,
        trace_txt,
        "",
        BRAND
    ]]

# ── main ────────────────────────────────────────────────────────────
def main():
    base = pathlib.Path(__file__).resolve().parent
    src  = base / "links.xlsx"
    if not src.exists():
        sys.exit("⚠️  Поместите links.xlsx в ту же папку")

    urls = pd.read_excel(src, header=None).iloc[:,0].dropna().tolist()
    print("Ссылок:", len(urls))

    headers = [
        "URL","Article","Name","SKU","PartNumber","Description","ColorImage",
        "Color","Size","Price","Weight","Visibility","AllImages","ColorImages",
        "Composition","Care","Traceability","CategoryPath","Brand"
    ]
    rows = []

    for i, u in enumerate(urls, 1):
        print(f"[{i}/{len(urls)}]  {u}", end=" ")
        try:
            rows.extend(rows_from_detail(get_detail(u), u))
            print("✓")
        except Exception as e:
            print("⚠️", e)
        time.sleep(1.0)           # задержка, чтоб не спамить

    pd.DataFrame(rows, columns=headers).to_excel(base/"result.xlsx", index=False)
    print("\n✅  result.xlsx сохранён")

if __name__ == "__main__":
    main()
