#!/usr/bin/env bash
set -euo pipefail

keyword=${1:-电脑桌}
report_scope=${2:-淘宝口径}
workdir=/tmp/market-brief
mkdir -p "$workdir"
profile=${BROWSER_PROFILE:-openclaw}

capture_snapshot() {
  local page="$1"
  local url="$2"
  local wait_text="${3:-}"
  local limit="${4:-260}"

  yuce-browser open "$url" >/dev/null 2>&1 || true
  openclaw browser wait --browser-profile "$profile" --load domcontentloaded --timeout-ms 15000 >/dev/null 2>&1 || true
  openclaw browser wait --browser-profile "$profile" --time 2000 >/dev/null 2>&1 || true
  if [ -n "$wait_text" ]; then
    openclaw browser wait --browser-profile "$profile" --text "$wait_text" --timeout-ms 12000 >/dev/null 2>&1 || true
  fi
  openclaw browser snapshot --browser-profile "$profile" --labels --limit "$limit" > "$workdir/${page}.snapshot.txt" || true
}

# Multi-page evidence collection
declare -A PAGE_URLS
PAGE_URLS[leaf_category]='https://hq.yucekj.com/?report-app=%2Freport%2F%23%2F#/scene/M_TB_TAPE_ANALYSIS/M_TB_TAPE_ANALYSIS_0/report-view/CZqcPFPRsZ'
PAGE_URLS[ranking_list]='https://hq.yucekj.com/?report-app=%2Freport%2F%23%2F#/scene/M_TB_RANKING_LIST/M_TB_RANKING_LIST_0/report-view/hEq4a98B7B'
PAGE_URLS[industry_distribution]='https://hq.yucekj.com/?report-app=%2Freport%2F%23%2F#/scene/M_TB_INSIGHT/M_TB_INDUSTRY_DISTRIBUTION/report-view/sfQrjDMn5l'
PAGE_URLS[surging_rank]='https://hq.yucekj.com/?report-app=%2Freport%2F%23%2F#/scene/M_TB_SURGING_RANK/M_TB_SURGING_RANK_0/report-view/CD6nSlf6pC'

LOGIN_URL='https://hq.yucekj.com/#/login?redirectUrl=https%3A%2F%2Fhq.yucekj.com%2F%23%2F'
HOME_URL='https://hq.yucekj.com/#/home?tab=TAOBAO_MNO'

yuce-browser open "$LOGIN_URL" >/dev/null 2>&1 || true
yuce-browser open "$HOME_URL" >/dev/null 2>&1 || true
openclaw browser wait --browser-profile "$profile" --time 1500 >/dev/null 2>&1 || true

capture_snapshot leaf_category "${PAGE_URLS[leaf_category]}" "销售金额" 360
capture_snapshot ranking_list "${PAGE_URLS[ranking_list]}" "榜单" 260
capture_snapshot industry_distribution "${PAGE_URLS[industry_distribution]}" "行业" 220
capture_snapshot surging_rank "${PAGE_URLS[surging_rank]}" "飙升" 280

yuce-browser requests --filter yucekj.com > "$workdir/requests.txt" || true

python3 - "$workdir" "$keyword" "$report_scope" <<'PY'
import json
import re
import sys
from collections import Counter
from datetime import datetime
from pathlib import Path

workdir = Path(sys.argv[1])
keyword = (sys.argv[2] or "").strip()
scope = (sys.argv[3] or "").strip()

pages = {
    "leaf_category": workdir / "leaf_category.snapshot.txt",
    "ranking_list": workdir / "ranking_list.snapshot.txt",
    "industry_distribution": workdir / "industry_distribution.snapshot.txt",
    "surging_rank": workdir / "surging_rank.snapshot.txt",
}
page_text = {k: (p.read_text(encoding="utf-8", errors="ignore") if p.exists() else "") for k, p in pages.items()}
request_text = (workdir / "requests.txt").read_text(encoding="utf-8", errors="ignore") if (workdir / "requests.txt").exists() else ""

ROW_RE = re.compile(r'row "([^\"]+)"')
PCT_RE = re.compile(r'^-?\d+(?:\.\d+)?%$')

def norm(s: str) -> str:
    return re.sub(r"[\s/（）()【】\[\]·\-_,，。:：;；]", "", (s or "")).lower()


def amount_to_num(s: str):
    if not s:
        return None
    t = s.replace(",", "").strip()
    mul = 1.0
    if t.endswith("亿"):
        mul = 1e8
        t = t[:-1]
    elif t.endswith("万"):
        mul = 1e4
        t = t[:-1]
    try:
        return float(t) * mul
    except Exception:
        return None


def pct_to_num(s: str):
    if not s:
        return None
    t = s.strip().replace("%", "")
    try:
        return float(t)
    except Exception:
        return None


def keyword_candidates(kw: str):
    out = []
    if kw:
        out.append(kw)
    cleaned = re.sub(r"(类目|市场|市场数据|市场分析|行业分析|类目分析|竞品分析|趋势分析|关键词|热词|飙升词)$", "", kw or "").strip()
    if cleaned and cleaned not in out:
        out.append(cleaned)
    alias_map = {
        "书架": ["书架", "架类书架", "置物架", "收纳架"],
        "电脑桌": ["电脑桌", "书桌", "学习桌"],
        "茶桌": ["茶桌", "茶几", "家用茶台"],
        "床垫": ["床垫", "席梦思", "乳胶床垫"],
    }
    for k, vals in alias_map.items():
        if k in (kw or ""):
            for v in vals:
                if v not in out:
                    out.append(v)
    return [x for x in out if len(x) >= 2]


def parse_leaf_rows(text: str):
    rows = []
    for row in ROW_RE.findall(text):
        if "查看 详情" not in row:
            continue
        m = re.match(r'^(.*?) 查看 详情 ([^ ]+) (-?\d+(?:\.\d+)?)%$', row)
        if not m:
            continue
        prefix = m.group(1).strip()
        amount_raw = m.group(2).strip()
        yoy_raw = f"{m.group(3)}%"
        toks = prefix.split()
        if len(toks) < 4:
            continue
        one, two, three = toks[0], toks[1], toks[2]
        leaf = " ".join(toks[3:])
        rows.append(
            {
                "row": row,
                "一级类目": one,
                "二级类目": two,
                "三级类目": three,
                "叶子类目": leaf,
                "销售金额": amount_raw,
                "销售金额同比": yoy_raw,
                "销售金额_num": amount_to_num(amount_raw),
                "销售金额同比_num": pct_to_num(yoy_raw),
            }
        )
    rows.sort(key=lambda r: (r["销售金额_num"] is not None, r["销售金额_num"] or -1), reverse=True)
    return rows


def parse_ranking_rows(text: str):
    rows = []
    for row in ROW_RE.findall(text):
        if not row.endswith(" 查看"):
            continue
        m = re.match(r'^(.*?) (\d{6,20}) (\S+) (\S+) 查看$', row)
        if not m:
            continue
        rows.append(
            {
                "商品名称": m.group(1).strip(),
                "商品ID": m.group(2).strip(),
                "店铺": m.group(3).strip(),
                "品牌": m.group(4).strip(),
                "row": row,
            }
        )
    return rows


def parse_surging_rows(text: str):
    rows = []
    for row in ROW_RE.findall(text):
        # 商品名 店铺 连续增长月份 近6月平均单价 销售额
        m = re.match(r'^(.*?) (\S+) (\d+) ([\d,]+(?:\.\d+)?) ([\d,]+(?:\.\d+)?(?:万|亿)?)$', row)
        if not m:
            continue
        rows.append(
            {
                "商品": m.group(1).strip(),
                "店铺": m.group(2).strip(),
                "连续增长月份": int(m.group(3)),
                "近6月平均单价": m.group(4).strip(),
                "销售金额": m.group(5).strip(),
                "销售金额_num": amount_to_num(m.group(5).strip()),
                "row": row,
            }
        )
    rows.sort(key=lambda r: (r["销售金额_num"] is not None, r["销售金额_num"] or -1), reverse=True)
    return rows


def parse_industry(text: str):
    m = re.search(r'一级类目 销售额 销售额同比\s+([^\s]+)\s+([\d,]+(?:\.\d+)?(?:万|亿)?)\s+(-?\d+(?:\.\d+)?)%', text)
    if not m:
        return None
    return {
        "一级类目": m.group(1),
        "销售额": m.group(2),
        "销售额_num": amount_to_num(m.group(2)),
        "销售额同比": f"{m.group(3)}%",
        "销售额同比_num": float(m.group(3)),
    }


leaf_rows = parse_leaf_rows(page_text.get("leaf_category", ""))
ranking_rows = parse_ranking_rows(page_text.get("ranking_list", ""))
surging_rows = parse_surging_rows(page_text.get("surging_rank", ""))
industry = parse_industry(page_text.get("industry_distribution", ""))

cand_norm = [norm(x) for x in keyword_candidates(keyword)]

def row_hit(text: str):
    n = norm(text)
    return any(c in n for c in cand_norm)

kw_leaf_candidates = [r for r in leaf_rows if row_hit(f"{r['三级类目']} {r['叶子类目']} {r['row']}")]
kw_leaf = kw_leaf_candidates[0] if kw_leaf_candidates else None

kw_rank = None
if kw_leaf and kw_leaf in leaf_rows:
    kw_rank = leaf_rows.index(kw_leaf) + 1

same_secondary = []
if kw_leaf:
    same_secondary = [r for r in leaf_rows if r["二级类目"] == kw_leaf["二级类目"]]

secondary_top3 = same_secondary[:3]
secondary_growth_top3 = sorted(same_secondary, key=lambda r: (r["销售金额同比_num"] is not None, r["销售金额同比_num"] or -999), reverse=True)[:3]

top10_amt = sum([r["销售金额_num"] or 0 for r in leaf_rows[:10]]) if leaf_rows else 0
kw_share_of_total = None
if kw_leaf and industry and industry.get("销售额_num"):
    if industry["销售额_num"] > 0 and kw_leaf.get("销售金额_num") is not None:
        kw_share_of_total = kw_leaf["销售金额_num"] / industry["销售额_num"] * 100

ranking_top20 = ranking_rows[:20]
ranking_shop_counter = Counter([r["店铺"] for r in ranking_top20])
ranking_brand_counter = Counter([r["品牌"] for r in ranking_top20])
ranking_kw_hits = [r for r in ranking_top20 if row_hit(f"{r['商品名称']} {r['店铺']} {r['品牌']}")]

surging_top10 = surging_rows[:10]
surging_kw_hits = [r for r in surging_top10 if row_hit(f"{r['商品']} {r['店铺']}")]

api_lines = [line.strip() for line in request_text.splitlines() if "/api/" in line]
api_lines = api_lines[-12:]

coverage = {
    "leaf_category": bool(page_text.get("leaf_category", "")),
    "ranking_list": bool(page_text.get("ranking_list", "")),
    "industry_distribution": bool(page_text.get("industry_distribution", "")),
    "surging_rank": bool(page_text.get("surging_rank", "")),
}

metrics = {
    "topic": keyword,
    "generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
    "scope": scope,
    "coverage": coverage,
    "industry": industry,
    "leaf": {
        "rows_count": len(leaf_rows),
        "keyword_row": kw_leaf,
        "keyword_rank": kw_rank,
        "keyword_share_of_total_pct": kw_share_of_total,
        "top10_amount_sum": top10_amt,
        "secondary_top3": secondary_top3,
        "secondary_growth_top3": secondary_growth_top3,
        "decline_top3": sorted(leaf_rows, key=lambda r: (r["销售金额同比_num"] is not None, r["销售金额同比_num"] or 999))[:3],
    },
    "ranking": {
        "rows_count": len(ranking_rows),
        "top20_unique_shop_count": len(ranking_shop_counter),
        "top5_shops": ranking_shop_counter.most_common(5),
        "top5_brands": ranking_brand_counter.most_common(5),
        "keyword_hits": ranking_kw_hits[:5],
    },
    "surging": {
        "rows_count": len(surging_rows),
        "top10": surging_top10,
        "keyword_hits": surging_kw_hits[:5],
    },
    "evidence": {
        "pages": [
            {"name": "叶子类目分析", "source": "leaf_category.snapshot.txt", "captured": coverage["leaf_category"]},
            {"name": "品牌店铺商品热榜", "source": "ranking_list.snapshot.txt", "captured": coverage["ranking_list"]},
            {"name": "行业分布", "source": "industry_distribution.snapshot.txt", "captured": coverage["industry_distribution"]},
            {"name": "飙升品榜单", "source": "surging_rank.snapshot.txt", "captured": coverage["surging_rank"]},
        ],
        "api_lines": api_lines,
    },
}

(workdir / "metrics.json").write_text(json.dumps(metrics, ensure_ascii=False, indent=2), encoding="utf-8")


def fmt_pct(v):
    if v is None:
        return "未在当前页面取到"
    return f"{v:.2f}%"


def fmt_ratio(v):
    if v is None:
        return "未在当前页面取到"
    return f"{v:.2f}%"


print(f"# {keyword}市场分析简报（增强版）")
print()
print("## 已抓取证据")
print(f"- 时间: {metrics['generated_at']}")
print(f"- 范围: {metrics['scope']}")
for p in metrics["evidence"]["pages"]:
    print(f"- 页面: {p['name']} ({'已抓取' if p['captured'] else '未抓取'})")
if industry:
    print(f"- 行业总览: 一级类目={industry['一级类目']}，销售额={industry['销售额']}，同比={industry['销售额同比']}")
else:
    print("- 行业总览: 未在当前页面取到")
if kw_leaf:
    print(f"- 关键词命中: {kw_leaf['row']}")
    print(f"- 关键词排名: 第{kw_rank}/{len(leaf_rows)}（按销售金额）")
else:
    print("- 关键词命中: 未在当前页面取到")
print(f"- 请求证据(API): {len(api_lines)}条（展示最近6条）")
for line in api_lines[-6:]:
    print(f"  - {line}")

print()
print("## 深度分析")
print("### 1) 规模与趋势")
if kw_leaf:
    print(f"- {keyword}销售金额={kw_leaf['销售金额']}，同比={kw_leaf['销售金额同比']}。")
    print(f"- {keyword}占一级类目销售额占比={fmt_ratio(kw_share_of_total)}。")
    if industry and kw_leaf.get("销售金额同比_num") is not None and industry.get("销售额同比_num") is not None:
        gap = kw_leaf["销售金额同比_num"] - industry["销售额同比_num"]
        direction = "跑赢" if gap >= 0 else "跑输"
        print(f"- 相对行业同比差值={gap:.2f}pct，{direction}行业大盘。")
    else:
        print("- 相对行业同比差值: 未在当前页面取到")
else:
    print("- 关键词行未命中，暂不输出规模趋势定量结论。")

print("### 2) 类目结构")
if kw_leaf and same_secondary:
    print(f"- {keyword}位于二级类目「{kw_leaf['二级类目']}」，同二级类目共抓取{len(same_secondary)}个叶子类目。")
    if secondary_top3:
        top_desc = "；".join([f"{r['叶子类目']}({r['销售金额']}, {r['销售金额同比']})" for r in secondary_top3])
        print(f"- 同二级类目销售TOP3: {top_desc}")
    if secondary_growth_top3:
        growth_desc = "；".join([f"{r['叶子类目']}({r['销售金额同比']})" for r in secondary_growth_top3])
        print(f"- 同二级类目增速TOP3: {growth_desc}")
else:
    print("- 未命中关键词二级类目，结构分析不完整。")

print("### 3) 竞争格局")
if ranking_rows:
    print(f"- 热榜样本: 抓取{len(ranking_rows)}行，TOP20覆盖店铺数={metrics['ranking']['top20_unique_shop_count']}。")
    if metrics["ranking"]["top5_shops"]:
        shop_desc = "；".join([f"{k}({v})" for k, v in metrics["ranking"]["top5_shops"][:3]])
        print(f"- 高频店铺(样本): {shop_desc}")
    if metrics["ranking"]["keyword_hits"]:
        hit_desc = "；".join([f"{r['商品名称']}[{r['店铺']}]" for r in metrics["ranking"]["keyword_hits"][:3]])
        print(f"- 关键词相关商品(热榜命中): {hit_desc}")
    else:
        print("- 关键词相关商品(热榜命中): 未在当前页面取到")
else:
    print("- 热榜数据未抓取到有效行。")

print("### 4) 增长机会与风险")
if surging_rows:
    print(f"- 飙升榜样本: 抓取{len(surging_rows)}行，TOP10中关键词命中={len(surging_kw_hits)}。")
    if surging_top10:
        top_surge = "；".join([f"{r['商品']}({r['销售金额']}, 连增{r['连续增长月份']}月)" for r in surging_top10[:3]])
        print(f"- 当前飙升代表样本: {top_surge}")
else:
    print("- 飙升榜数据未抓取到有效行。")

if metrics["leaf"]["decline_top3"]:
    decline_desc = "；".join([f"{r['叶子类目']}({r['销售金额同比']})" for r in metrics["leaf"]["decline_top3"][:3]])
    print(f"- 同页下滑风险叶子类目TOP3: {decline_desc}")

print()
print("## 可执行建议")
if kw_leaf:
    print(f"- P1: 围绕「{kw_leaf['二级类目']}->{kw_leaf['叶子类目']}」拆分价格带与主卖点，先对齐同比下滑原因。")
else:
    print(f"- P1: 先在叶子类目页精确命中「{keyword}」后再做定量策略。")
print("- P1: 以热榜TOP店铺与品牌为对标，复刻高频素材结构（标题词/卖点图/价格锚点）。")
print("- P2: 用飙升榜样本补充新品池，优先测试连续增长月份>=5的商品方向。")
print("- P2: 对同比显著下滑类目做止损策略（预算下调+创意替换+词包重组）。")
print("- P3: 补抓价格段布局、需求趋势、关键词布局三页后再做投放预算分配。")

print()
print("## 风险与缺口")
if not kw_leaf:
    print("- 关键词主行未命中，当前报告存在样本偏差风险。")
if kw_leaf and kw_leaf.get("销售金额同比") == "未在当前页面取到":
    print("- 缺失关键词同比字段，无法做趋势判断。")
print("- 当前脚本未稳定抓到销售数量/转化率字段，件数口径需在详情/字段面板补抓。")
print("- 若页面筛选条件被改动且未点查询，指标可能失真（已要求SOP强制点查询）。")

print()
print("## 下一步")
print("- 补抓: 价格段布局 + 需求趋势分析 + 关键词布局分析（同关键词、同时间窗）。")
print("- 追加: 近3个月滚动对比，验证当前同比结论是否持续。")
print("- 输出: 可选生成“策略执行单”（词包/价格带/竞店清单）。")
print()
print(f"（结构化指标文件: {workdir / 'metrics.json'}）")
PY
