#!/usr/bin/env python3
"""
报价表OCR解析器 v3 — 更全面分类
"""
import re, os
from collections import defaultdict, OrderedDict, Counter

WORKDIR = '/home/agentuser/work/20260514'

# ============================
# OCR错误修复
# ============================
OCR_FIXES = {
    'IQ00': 'iQOO', 'IQOO': 'iQOO',
    'Neoll': 'Neo11', 'Neol1': 'Neo11',
    'Proll寸': 'Pro11寸',
    'Windowsll': 'Windows11',
    'Ultraz ': 'Ultra2 ', 'Ultra2f ': 'Ultra2 ', 'U1tra': 'Ultra', '14U1tra': '14Ultra',
    'atch5 46MM': 'Watch5 46MM', 'Batch4 ': 'Watch4 ',
    '29 冰雪奇缘': 'Z9 冰雪奇缘',
    'Z10 Trubo': 'Z10 Turbo',
    'WWatch5': 'Watch5',
    'X801': 'X80i',
    'A61': 'A6i',
    'iPad5': 'iQOO Pad5',
    'iPad5 Pro': 'iQOO Pad5 Pro',
    'iPad2 Pro': 'iQOO Pad2 Pro',
}

def apply_ocr_fixes(s):
    for old, new in OCR_FIXES.items():
        s = s.replace(old, new)
    # OCR将"寸"识别为"+": 型号末尾"16+"→"16寸"
    s = re.sub(r'\b16\+$', '16寸', s)
    # 清理前置的价格注释（如"5530热卖 2025款 iPad" → "2025款 iPad"）
    s = re.sub(r'^\d{3,5}(?:推荐|热卖|批发)\d*\s*', '', s)
    # 清理尾部标记（如 "5530热卖" "推荐2" "热卖3"）
    s = re.sub(r'\s*\d{0,5}(?:推荐|热卖|批发)\d*\s*$', '', s)
    # 清理中间注释（如"蓝色 1330热卖 MatePad"→"蓝色 MatePad"）
    s = re.sub(r'\s*\d{0,5}(?:推荐|热卖|批发)\d*\s+', ' ', s)
    # 清理末尾拼接的下一产品（如"蓝色9900 荣耀Magic V5"→""）
    # 特征：中文字+数字(4-5位)+空格+产品名
    s = re.sub(r'[\u4e00-\u9fff]+\d{4,5}\s+\S.*$', '', s)
    # 清理拼接留下的尾部分隔符
    s = re.sub(r'[/#@!]+\s*$', '', s).strip()
    return s

def clean_price(s):
    s = s.strip()
    s = re.sub(r'(推荐|热卖|批发)\d*', '', s)
    s = re.sub(r'[^\d/]', '', s)
    return s

def is_price(s):
    """判断s是否为有效价格（先清注解，再校验）"""
    # 第一步：去掉注解词（推荐/热卖/批发+编号），避免带中文注解放过价格
    s = re.sub(r'(推荐|热卖|批发)\d*', '', s.strip())
    # 第二步：检查清理后是否仍含中文（如"活力版 8G+256G 黑色"→"活力版 黑色"仍有中文）
    if re.search(r'[\u4e00-\u9fff]', s):
        return False
    # 排除内存规格（如12G+256G、16G+1T、8G+128G等）
    if re.search(r'\d+\s*[GT]\s*\+?\s*\d+', s, re.IGNORECASE):
        return False
    s = clean_price(s)
    # 价格必须是3~5位数字（或带/的区间），不能超过50000
    m = re.match(r'^(\d{3,5})(?:/(\d{3,5}))?$', s)
    if m:
        p1 = int(m.group(1))
        if p1 > 50000:
            return False
        if m.group(2):
            p2 = int(m.group(2))
            if p2 > 50000:
                return False
        return True
    return False

# ============================
# 强大的品牌分类
# ============================
def classify(model, default='其他'):
    """按关键词分类（保留空格版本 + 去空格版本双重匹配）"""
    m_orig = model.lower()          # 保留空格
    m = m_orig.replace(' ', '')     # 去空格（用于单个字词匹配）
    
    # === 苹果手机 ===
    if any(kw in m for kw in ['苹果17', '苹果16', '苹果15', '苹果14', '苹果13', '苹果12', '苹果11',
                               'iphone17', 'iphone16', 'iphone15', 'iphone14', 'iphone13',
                               'iphone12', 'iphone11', 'iphonese',
                               'iphoneair', 'iphone air']):
        return '苹果手机'
    
    # === 华为儿童手表（提前拦截，避免"华为儿童手表5"被华为手机"华为"关键词匹配）===
    if any(kw in m for kw in ['华为儿童', '华为儿童手表']):
        return '华为儿童手表'
    
    # === 手环（提前拦截，避免"华为手环"被华为手机"华为"关键词匹配）===
    if any(kw in m for kw in ['手环']):
        return '华为手表'
    
    # === 华为配件/非手机（提前拦截，避免"华为原装背包"等被华为手机"华为"关键词匹配）===
    if any(kw in m for kw in ['华为原装背包', '华为m-pencil', '华为原装']):
        return '其他'
    
    # === 华为手机 ===
    if any(kw in m for kw in ['华为', 'huawei', 'pura', 'nova',
                               '畅享', '畅玩',
                               'pocket4', 'pocket3', 'pocket2',
                               'matex', 'mates', 'matext', 'mate rs']):
        return '华为手机'
    # 华为Mate/Pura型号（用原文本匹配避免空格问题）
    if any(kw in m_orig for kw in ['mate80', 'mate70', 'mate60', 'mate50', 'mate40',
                                    'pura90', 'pura80', 'pura70',
                                    'nova15', 'nova14', 'nova13', 'nova12', 'nova11']):
        return '华为手机'
    
    # === 荣耀手机 ===
    if any(kw in m for kw in ['荣耀', 'magic8', 'magic7', 'magic6', 'magic5',
                               'magicrsr', 'magicspro', 'magicgt',
                               '荣耀gt', '荣耀200', '荣耀300', '荣耀100',
                               '荣耀90', '荣耀80', '荣耀70', '荣耀60', '荣耀50',
                               '荣耀x', '荣耀play', '荣耀power', '荣耀win']):
        return '荣耀手机'
    if any(kw in m_orig for kw in ['magicv', 'magicv flip', 'magicvflip',
                                    'magic gt', 'magic rsr']):
        return '荣耀手机'
    
    # === 华为耳机Freelace（提前拦截，避免acepro子串误匹配为OPPO）===
    if any(kw in m for kw in ['freelace']):
        return '华为耳机'
    
    # === 平板（品牌专用在前，防误匹配）—— 必须在VIVO/iQOO手机之前 ===
    # 荣耀MagicPad
    if any(kw in m_orig for kw in ['magic pad', 'magicpad', '荣耀magicpad']):
        return '荣耀平板'
    if any(kw in m for kw in ['荣耀平板', '荣耀pad']):
        return '荣耀平板'
    if any(kw in m_orig for kw in ['iqoo pad', 'iqoo平板']):
        return 'IQOO平板'
    if any(kw in m_orig for kw in ['vivo pad', 'vivo平板', 'vivopad']):
        return 'vivo平板'
    if any(kw in m_orig for kw in ['oppo pad', 'oppo平板', 'oppopad']):
        return 'OPPO平板'
    if any(kw in m_orig for kw in ['一加平板', '一加 pad']):
        return '一加平板'
    # 华为/苹果平板检查必须在通用pad关键词之前，避免MatePad的"pad2"子串误匹配OPPO
    if any(kw in m for kw in ['华为平板', 'matepad', '华为mate']):
        return '华为平板'
    if any(kw in m for kw in ['ipad', '苹果ipad', '苹果ip']):
        return '苹果平板'
    if any(kw in m_orig for kw in ['ipad pro', 'ipad air', 'ipad mini']):
        return '苹果平板'
    # 通用pad关键词 → OPPO平板（前面品牌专用的pad已全部拦截）
    if any(kw in m for kw in ['pad3', 'pad4', 'pad4pro', 'pad5', 'pad5pro',
                               'padair5', 'padair2', 'pad2']):
        return 'OPPO平板'
    
    # === iQOO手机（单独分类，不计入VIVO）===
    if any(kw in m for kw in ['iqoo', 'iq00']):
        return 'iQOO手机'
    
    # === VIVO手机 ===
    # X Fold、X300、X200是VIVO专属型号
    if any(kw in m for kw in ['xfold', 'x300', 'x200', 'x100', 'x90', 'x80',
                               'x70', 'x60',
                               's50', 's30', 's20', 's19', 's18',
                               'y500', 'y300', 'y200', 'y100',
                               'vivo', 'vivox', 'vivos', 'vivoy', 'vivot']):
        # MIX FOLD是小米手机，不是VIVO
        if 'mixfold' in m or 'mixf' in m:
            pass
        else:
            return 'vivo手机'
    if any(kw in m_orig for kw in ['vivo', 'vivo x', 'vivo s', 'vivo y',
                                    'x fold', 'x flip']):
        # MIX FOLD是小米，不是VIVO
        if 'mix fold' in m_orig or 'mixfold' in m or 'mixf' in m:
            pass
        else:
            return 'vivo手机'
    
    # === 一加手机（在OPPO之前，避免被ace5/ace3等误匹配为OPPO）===
    if any(kw in m for kw in ['一加', '-加', 'oneplus']):
        return '一加手机'
    if any(kw in m_orig for kw in ['一加', 'oneplus']):
        return '一加手机'
    
    # === OPPO手机 ===
    if any(kw in m_orig for kw in ['oppo', 'oppo find', 'oppo reno', 'oppo a', 'oppo k',
                                    'find n', 'find x', 'find x6', 'find x7', 'find x8', 'find x9',
                                    'find n5', 'find n6', 'find n7',
                                    'reno', 'a6 pro', 'a5 pro',
                                    '一加', 'oneplus',
                                    'ace 5', 'ace 3', 'ace pro']):
        return 'OPPO手机'
    if any(kw in m for kw in ['oppo', 'oppofind', 'opporeno', 'oppoa', 'oppok',
                               'findn', 'findx',
                               'reno', 'a6pro', 'a5pro',
                               'ace5', 'ace3', 'acepro',
                               'a6x', 'a6v', 'a6i', 'a61', 'a5x', 'a5h1',
                               '一加', 'oneplus']):
        return 'OPPO手机'
    
    # === 小米/红米手机 ===
    if any(kw in m for kw in ['红米', 'redmi', 'redm',
                               'mixfold', 'mixf',
                               'k90', 'k80', 'k70', 'k60',
                               'note15', 'note14', 'note13', 'note12',
                               'turbo', 'turbo4', 'turbo6',
                               '小米']):
        if '手表' in m or 'watch' in m or '手环' in m:
            pass
        else:
            return '小米手机'
    if any(kw in m_orig for kw in ['小米17', '小米16', '小米15', '小米14', '小米13', '小米12', '小米11', '小米10',
                                    'mix fold', 'mix fold4', 'mix fold5', '小米mix']):
        if '手表' in m or 'watch' in m or '手环' in m:
            pass
        else:
            return '小米手机'
    
    # === 努比亚手机 ===
    if any(kw in m for kw in ['努比亚', 'nubia', 'z70', 'z60', 'z50',
                               '红魔', 'redmagic']):
        return '努比亚手机'
    
    # === 苹果笔记本（提前检查，避免Mac Studio的ultra9等子串误匹配华为笔记本）===
    if re.match(r'^[A-Z0-9][A-Z0-9]?[0-9][A-Z0-9]?\s', model):
        first = model.split()[0]
        # MacBook Neo 全系列
        if re.match(r'^(FA|FH|FN|FK|FD|FF|FC|FJ|FE|FG)\d', first):
            return '苹果笔记本'
        # MacBook Air 全系列（13寸+15寸+M系全代）
        if re.match(r'^(HE|HA|HF|HC|HG|HD|H7|HH|H8|HJ|HK|VH|VD|V9|VK|VQ|VE|VA|VT|VN|VF|VC)\d', first):
            return '苹果笔记本'
        # MacBook Air M4 13寸及老款库存代码
        if re.match(r'^(12[0-9]|OY|DA|W9|18[0-9])\s', first):
            return '苹果笔记本'
        # MacBook Pro M5/M5Pro/M5Max (14寸)
        if re.match(r'^(3[DEFG]|E[0-9]|DR|DN|LV|DT|DP)\d', first):
            return '苹果笔记本'
        # MacBook Pro M4/M4Pro/M4Max
        if re.match(r'^(2[UVWX]|X0|X1|2[HI]|30|31)\d', first):
            return '苹果笔记本'
        # MacBook Pro M3/M3Pro/M3Max
        if re.match(r'^(L7|7[JK]|X[3-8])\d', first):
            return '苹果笔记本'
        # MacBook Pro M2/M2Pro/M2Max (16寸)
        if re.match(r'^(WE|WA|HU)\d', first):
            return '苹果笔记本'
        # Mac mini
        if re.match(r'^(YT|X4|9[DEG])\d', first):
            return '苹果笔记本'
        # iMac
        if re.match(r'^(UC|UE)\d', first):
            return '苹果笔记本'
    if any(kw in m for kw in ['macbook', 'macbook', 'macbook pro', 'macbook air', 'macbook neo',
                               'mac mini', 'mac studio', 'mac pro', 'imac',
                               'mac']):
        return '苹果笔记本'

    # === 华为笔记本 ===
    if any(kw in m for kw in ['matebook', 'matebook',
                               'i5-', 'i7-', 'i9-', '15-',
                               'ultra5', 'ultra7', 'ultra9',
                               'intel', '华为笔记本',
                               '15-13420h', 'i5-13420h', 'i7-1260u']):
        # 排除Mac（Mac Studio的M3Ultra 96G含"ultra9"子串）
        if 'mac studio' in m_orig or 'macbook' in m_orig or 'mac mini' in m_orig or 'imac' in m_orig:
            pass
        else:
            return '华为笔记本'

    # === 三星手机 ===
    if any(kw in m for kw in ['三星', 'samsung', 'galaxy', 's25', 's24', 's23', 's22', 's21',
                               'z fold', 'z flip', 'a55', 'a56', 'a54', 'a53', 'a35', 'a36',
                               'tab s', 'galaxy tab', 'note20', 'note10']):
        return '三星手机'

    # === 华为手表（提前检查，避免GT6/GT5被真我手机匹配）===
    if any(kw in m_orig for kw in ['watch gt', 'watch 6', 'watch 5', 'watch 4', 'watch 3',
                                    'watch d', 'watch fit', 'watch ultimate', 'watch s', 'watch x',
                                    'watch buds']):
        return '华为手表'

    # === 真我手机 ===
    if any(kw in m for kw in ['真我', 'realme', 'realme',
                               '真我14', '真我13', '真我12', '真我gt',
                               'gt7', 'gt6', 'gt5', 'neo10', 'neo7', 'neo6',
                               'neo10pro']):
        return '真我手机'

    # === 手表 ===
    if any(kw in m for kw in ['ultra3', 'ultra2', 's11', 's10', 's9',
                               'gps款', '蜂窝版', '蜂窝款', '苹果手表',
                               'watch ultra']):
        return '苹果手表'
    if any(kw in m_orig for kw in ['watch se', 'apple watch']):
        return '苹果手表'
    if any(kw in m for kw in ['watch5', 'watch4', 'watch3',
                               '华为手表', '华为手环',
                               'fit3', 'fit4', 'fit5',
                               '华为儿童', '手环',
                               'freelace']):
        return '华为手表'
    if any(kw in m_orig for kw in ['watch gt', 'watch d', 'watch buds', 'watch buds2',
                                    'watch 5', 'watch 4', 'watch 3',
                                    'watch fit', 'watch ultimate', 'watch s', 'watch x']):
        return '华为手表'
    if any(kw in m for kw in ['小天才', 'z11', 'z10', 'z9', 'z8', 'z7', 'z6', 'z5', 'z3', 'd3s', 'd2a']):
        return '小天才手表'
    # d3必须单独出现（含空格边界），避免匹配fold3中的d3
    if re.search(r'(^|\s)d3(\s|$)', m_orig):
        return '小天才手表'

    # === 耳机 ===
    if any(kw in m for kw in ['华为耳机', 'freelace', 'freebuds', 'freebus', '华为free',
                               'freeclip', 'freeclip2']):
        return '华为耳机'
    if any(kw in m for kw in ['三星耳机', '三星buds', 'galaxy buds']):
        return '三星耳机'
    
    # === 配件 ===
    if any(kw in m for kw in ['苹果充电', '苹果20w', '苹果30w', '苹果70w', '苹果140w',
                               '苹果原装', '苹果数据', '苹果硅胶', '苹果皮套',
                               'airpods', 'airpods', 'airtag', 'airtag',
                               '原装充电', '原装数据']):
        return '苹果配件'
    
    return '其他'

# ============================
# 解析HTML表格
# ============================
def parse_img1(data):
    """图片1: 4列布局"""
    categories = ['苹果手机', '苹果平板', '华为手机', '荣耀手机']
    items = []
    
    for s in ['1','2','3','4']:
        html = data['1'].get(s, '')
        if not html:
            continue
        
        tr_blocks = re.findall(r'<tr[^>]*>(.*?)</tr>', html, re.DOTALL)
        
        for tr in tr_blocks:
            vals = []
            for m in re.finditer(r'<t[dh][^>]*>(.*?)</t[dh]>', tr, re.DOTALL):
                content = re.sub(r'<[^>]+>', '', m.group(1)).strip()
                if content:
                    vals.append(content)
            
            if len(vals) < 2:
                continue
            
            # 智能扫描：逐个判断每个值是型号还是价格还是颜色
            i = 0
            while i < len(vals):
                v = vals[i].strip()
                
                # 跳过纯颜色/描述（短文本，非价格）
                if len(v) <= 6 and not is_price(v) and not re.match(r'^[\d]+', v):
                    i += 1
                    continue
                
                # v是价格 → 前面i-1应该是型号
                if is_price(v):
                    if i > 0:
                        model = vals[i-1].strip()
                        price = clean_price(v)
                        if len(model) >= 4 and price:
                            cleaned_model = apply_ocr_fixes(model)
                            cat = classify(cleaned_model, '其他')
                            items.append((cat, cleaned_model, price))
                    i += 1
                    continue
                
                # v是型号，下一个是价格 → (model, price)
                if i + 1 < len(vals) and is_price(vals[i+1]):
                    model = v
                    price = clean_price(vals[i+1])
                    if len(model) >= 4 and price:
                        cleaned_model = apply_ocr_fixes(model)
                        cat = classify(cleaned_model, '其他')
                        items.append((cat, cleaned_model, price))
                    i += 2
                    continue
                
                # v是型号，下一个是颜色/描述，再下一个是价格 → (model, color, price)
                if i + 2 < len(vals) and is_price(vals[i+2]):
                    model = v + ' ' + vals[i+1].strip()
                    price = clean_price(vals[i+2])
                    if len(model) >= 4 and price:
                        cleaned_model = apply_ocr_fixes(model)
                        cat = classify(cleaned_model, '其他')
                        items.append((cat, cleaned_model, price))
                    i += 3
                    continue
                
                i += 1
    
    return items

def parse_img2(data):
    """图片2: 多品牌多列布局"""
    items = []
    
    for s in ['1','2','3','4']:
        html = data['2'].get(s, '')
        if not html:
            continue
        
        tr_blocks = re.findall(r'<tr[^>]*>(.*?)</tr>', html, re.DOTALL)
        
        for tr in tr_blocks:
            vals = []
            for m in re.finditer(r'<t[dh][^>]*>(.*?)</t[dh]>', tr, re.DOTALL):
                content = re.sub(r'<[^>]+>', '', m.group(1)).strip()
                if content:
                    vals.append(content)
            
            if len(vals) < 2:
                continue
            
            i = 0
            while i < len(vals):
                v = vals[i]
                if is_price(v):
                    i += 1
                    continue
                
                # (model, price)
                if i + 1 < len(vals) and is_price(vals[i+1]):
                    model = apply_ocr_fixes(v)
                    price = clean_price(vals[i+1])
                    if model and price and len(model) >= 4:
                        cat = classify(model)
                        items.append((cat, model, price))
                    i += 2
                # (model, color, price) 
                elif i + 2 < len(vals) and is_price(vals[i+2]):
                    model = apply_ocr_fixes(v + ' ' + vals[i+1])
                    price = clean_price(vals[i+2])
                    if model and price and len(model) >= 4:
                        cat = classify(model)
                        items.append((cat, model, price))
                    i += 3
                # (brand, model, color, price) or (model, color1, color2, price)
                elif i + 3 < len(vals) and is_price(vals[i+3]):
                    # 尝试 (brand model, color, price) 
                    model = apply_ocr_fixes(v + ' ' + vals[i+1] + ' ' + vals[i+2])
                    price = clean_price(vals[i+3])
                    if model and price and len(model) >= 4:
                        cat = classify(model)
                        items.append((cat, model, price))
                    i += 4
                else:
                    i += 1
    
    return items

# ============================
# 生成HTML
# ============================
def generate_html(items, page_title, target_cats):
    cat_data = defaultdict(list)
    for cat, model, price in items:
        cat_data[cat].append((model, price))
    
    def sort_key(item):
        cat, model, price = item
        # OPPO手机按配置排序（低→高）
        if cat == 'OPPO手机':
            m = re.search(r'(\d+)G\s*\+\s*(\d+)[GT]', model)
            if m:
                ram = int(m.group(1))
                storage = int(m.group(2))
                return (0, ram, storage)
            return (1,)
        # 华为手机：4列网格中有两列都是华为手机，按行交替。按系列名归组。
        if cat == '华为手机':
            # nova系列：按代数降序（15→14→13→12→Flip）
            nova_m = re.match(r'nova\s*(\d+)', model, re.I)
            if nova_m:
                gen = int(nova_m.group(1))
                order = 15 - gen  # 15→0, 14→1, 13→2, 12→3
                return (f'znovagen{order:03d}',)
            if re.match(r'nova', model, re.I):
                return ('znovagen999',)  # nova Flip排最后
            # 其他系列按基础名排列
            base = re.match(r'^([\u4e00-\u9fffA-Za-z0-9]+(?:\s*[\u4e00-\u9fffA-Za-z0-9\+]+){0,2})', model)
            if base:
                return (base.group(1),)
            return (model,)
        return (0,)
    
    cat_order = {c: i for i, c in enumerate(target_cats)}
    page_items = [(c, m, p) for c, m, p in items if c in cat_order]
    page_items.sort(key=lambda x: (cat_order.get(x[0], 999), sort_key(x)))
    
    grouped = OrderedDict()
    for cat, model, price in page_items:
        if cat not in grouped:
            grouped[cat] = []
        grouped[cat].append((model, price))
    
    brand_colors = {
        '苹果手机': '#555555', '华为手机': '#CF0A2C', '荣耀手机': '#003366',
        'vivo手机': '#415FFF', 'iQOO手机': '#EB0029', 'OPPO手机': '#1A7A3D', '小米手机': '#FF6900',
        '努比亚手机': '#8B0000', '三星手机': '#1428A0', '一加手机': '#EB0029', '真我手机': '#FFD700',
        '苹果平板': '#555555', '荣耀平板': '#003366', '华为平板': '#CF0A2C', 'vivo平板': '#415FFF',
        'OPPO平板': '#1A7A3D', 'IQOO平板': '#EB0029', '一加平板': '#EB0029', '苹果手表': '#555555',
        '华为手表': '#CF0A2C', '小天才手表': '#FF6B9D', '华为儿童手表': '#CF0A2C', '苹果笔记本': '#555555',
        '华为笔记本': '#CF0A2C', '苹果配件': '#555555', '华为耳机': '#CF0A2C',
        '三星耳机': '#1428A0',
    }
    
    sections_html = ''
    total_items = 0
    for cat, items_list in grouped.items():
        if not items_list:
            continue
        color = brand_colors.get(cat, '#666666')
        count = len(items_list)
        total_items += count
        
        rows = ''
        for model, price in items_list:
            rows += f'''            <tr>
                <td class="model">{model}</td>
                <td class="price">{price}</td>
            </tr>
'''
        sections_html += f'''        <section class="category" id="cat-{cat}">
            <h2 class="cat-title" style="border-left: 4px solid {color}; padding-left: 12px;">
                {cat} <span class="count">{count}</span>
            </h2>
            <table>
                <thead>
                    <tr>
                        <th style="width:78%">型号</th>
                        <th style="width:22%">批发价</th>
                    </tr>
                </thead>
                <tbody>
{rows}                </tbody>
            </table>
        </section>
'''
    
    nav_items = ''
    for cat in grouped:
        nav_items += f'            <a href="#cat-{cat}">{cat}</a>\n'
    
    if '手机' in page_title:
        page_links = '<a href="phone.html" class="active">📱 手机</a><a href="pad.html">📟 平板·手表</a><a href="pc.html">💻 电脑·配件</a>'
    elif '平板' in page_title:
        page_links = '<a href="phone.html">📱 手机</a><a href="pad.html" class="active">📟 平板·手表</a><a href="pc.html">💻 电脑·配件</a>'
    else:
        page_links = '<a href="phone.html">📱 手机</a><a href="pad.html">📟 平板·手表</a><a href="pc.html" class="active">💻 电脑·配件</a>'
    
    html = f'''<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>悦诚电子 - {page_title}</title>
    <style>
        * {{ margin: 0; padding: 0; box-sizing: border-box; }}
        body {{ background: #1a1a1a; color: #e0e0e0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; padding-top: 100px; }}
        .nav-top {{ position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: #222; padding: 10px 15px; display: flex; align-items: center; justify-content: center; gap: 10px; border-bottom: 1px solid #333; overflow-x: auto; white-space: nowrap; }}
        .nav-top a {{ color: #aaa; text-decoration: none; padding: 6px 16px; border-radius: 6px; font-size: 14px; transition: all 0.2s; }}
        .nav-top a:hover, .nav-top a.active {{ background: #e67e22; color: #fff; }}
        .nav-top .title {{ color: #e67e22; font-weight: bold; font-size: 16px; margin-right: 10px; }}
        .nav-cat {{ position: fixed; top: 48px; left: 0; right: 0; z-index: 99; background: #1e1e1e; padding: 8px 15px; display: flex; justify-content: center; gap: 6px; overflow-x: auto; white-space: nowrap; border-bottom: 1px solid #333; }}
        .nav-cat a {{ color: #999; text-decoration: none; padding: 4px 12px; border-radius: 4px; font-size: 13px; transition: all 0.2s; }}
        .nav-cat a:hover {{ background: #333; color: #e67e22; }}
        .container {{ max-width: 800px; margin: 0 auto; padding: 15px; }}
        .cat-title {{ font-size: 18px; font-weight: bold; margin: 20px 0 10px; display: flex; align-items: center; gap: 8px; }}
        .count {{ font-size: 12px; color: #999; background: #333; padding: 2px 8px; border-radius: 10px; }}
        table {{ width: 100%; border-collapse: collapse; margin-bottom: 20px; background: #1c1c1c; border-radius: 8px; overflow: hidden; }}
        th, td {{ padding: 8px 12px; text-align: left; border-bottom: 1px solid #2a2a2a; }}
        thead th {{ background: #222; color: #999; font-weight: 500; font-size: 12px; }}
        tbody tr:hover {{ background: #252525; }}
        .model {{ font-size: 12px; word-break: break-word; }}
        .price {{ font-size: 13px; font-weight: bold; color: #e74c3c; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 120px; }}
        .footer {{ text-align: center; padding: 30px; color: #666; font-size: 12px; }}
        .total {{ text-align: center; color: #e67e22; font-size: 14px; padding: 10px; }}
    </style>
</head>
<body>
    <nav class="nav-top">
        <span class="title">悦诚电子</span>
        {page_links}
    </nav>
    <nav class="nav-cat">
{nav_items}    </nav>
    <div class="container">
        <div class="total">共 {total_items} 件商品</div>
{sections_html}        <div class="footer">
            <p>悦诚电子 · 郑州市金水区东风路百脑汇</p>
            <p>价格多变，电询为准 微信支付1千元收1元手续费</p>
        </div>
    </div>
</body>
</html>'''
    return html, total_items

# ============================
# 主流程
# ============================
def main():
    data = {}
    for img in ['1', '2']:
        data[img] = {}
        for s in ['1','2','3','4']:
            path = f'{WORKDIR}/ocr_{img}_s{s}.txt'
            if os.path.exists(path):
                data[img][s] = open(path, encoding='utf-8').read()
    
    items1 = parse_img1(data)
    items2 = parse_img2(data)
    
    seen = set()
    all_items = []
    for items_src in [items1, items2]:
        for cat, model, price in items_src:
            key = (model, price)
            if key not in seen:
                seen.add(key)
                all_items.append((cat, model, price))
    
    print(f"图片1: {len(items1)} 条, 图片2: {len(items2)} 条, 合并: {len(all_items)} 条")
    
    cat_counts = defaultdict(int)
    for cat, model, price in all_items:
        cat_counts[cat] += 1
    print("\n分类统计:")
    for cat, cnt in sorted(cat_counts.items(), key=lambda x: -x[1]):
        print(f"  {cat}: {cnt}")
    
    # 修正: 小天才Z11/Z10 (有内存→vivo, 无内存→小天才)
    fixed = []
    for cat, model, price in all_items:
        if cat == 'vivo手机' and re.match(r'Z(?:11|10)(?!.*\d+G\+\d+G)', model):
            fixed.append(('小天才手表', model, price))
        else:
            fixed.append((cat, model, price))
    
    # Watch5/Watch4在华为手表
    fixed2 = []
    for cat, model, price in fixed:
        if cat == '小天才手表' and any(kw in model for kw in ['Watch5', 'Watch4', 'Watch Buds', 'Buds2', 'atch5', 'Watch 5', 'Watch 4']):
            fixed2.append(('华为手表', model, price))
        else:
            fixed2.append((cat, model, price))
    
    # Ultra系列在苹果手表
    fixed3 = []
    for cat, model, price in fixed2:
        if cat != '苹果手表' and any(kw in model for kw in ['Ultra3', 'Ultra2', 'S11', 'S10', 'GPS款', '蜂窝版', 'Watch SE']):
            fixed3.append(('苹果手表', model, price))
        else:
            fixed3.append((cat, model, price))
    
    all_items = fixed3

    # === 手表前缀补充：给GPS款/蜂窝版加上系列前缀 ===
    WATCH_PREFIX_MAP = {
        # S11 42MM
        'U94':'S11 42MM ','UA4':'S11 42MM ','UG4':'S11 42MM ','UH4':'S11 42MM ',
        'UN4':'S11 42MM ','UP4':'S11 42MM ','UT4':'S11 42MM ',
        '924':'S11 42MM ','954':'S11 42MM ','964':'S11 42MM ',
        '984':'S11 42MM ','9A4':'S11 42MM ','9G4':'S11 42MM ',
        # S11 46MM
        'VG4':'S11 46MM ','VH4':'S11 46MM ','VN4':'S11 46MM ','VP4':'S11 46MM ',
        'VT4':'S11 46MM ','VU4':'S11 46MM ','VW4':'S11 46MM ',
        'D94':'S11 46MM ','DA4':'S11 46MM ','DD4':'S11 46MM ',
        'DE4':'S11 46MM ','DG4':'S11 46MM ','DK4':'S11 46MM ','DL4':'S11 46MM ',
        'DW4':'S11 46MM ','DY4':'S11 46MM ','DT4':'S11 46MM ',
        # S10 42MM
        '1M3':'S10 42MM ','1P3':'S10 42MM ','1R3':'S10 42MM ',
        '1Q3':'S10 42MM ','1L3':'S10 42MM ',
        'XM3':'S10 42MM ','XN3':'S10 42MM ','XQ3':'S10 42MM ',
        'XR3':'S10 42MM ','XJ3':'S10 42MM ','XK3':'S10 42MM ','XP3':'S10 42MM ',
        # S10 46MM
        '263':'S10 46MM ','273':'S10 46MM ','293':'S10 46MM ',
        '2A3':'S10 46MM ','203':'S10 46MM ','223':'S10 46MM ',
        '283':'S10 46MM ','243':'S10 46MM ',
        'YJ3':'S10 46MM ','YK3':'S10 46MM ','YM3':'S10 46MM ',
        'YN3':'S10 46MM ','YG3':'S10 46MM ','YL3':'S10 46MM ',
        # S9 45MM
        '9A3':'S9 45MM ',
        # Watch SE3 2025 40mm
        'HA4':'Watch SE3 2025款 40mm ','HD4':'Watch SE3 2025款 40mm ',
        'H44':'Watch SE3 2025款 40mm ','PR4':'Watch SE3 2025款 40mm ',
        'PQ4':'Watch SE3 2025款 40mm ','PM4':'Watch SE3 2025款 40mm ',
        'PN4':'Watch SE3 2025款 40mm ',
        # Watch SE3 2025 44mm
        'PX4':'Watch SE3 2025款 44mm ',
        # Watch SE 2024 40mm
        'EX3':'Watch SE 2024款 40mm ','EY3':'Watch SE 2024款 40mm ',
        'HK3S':'Watch SE 2024款 40mm ','HU3S':'Watch SE 2024款 40mm ',
        # Watch SE 2024 44mm
        'F83':'Watch SE 2024款 44mm ','F93':'Watch SE 2024款 44mm ',
        'FG3':'Watch SE 2024款 44mm ','J13':'Watch SE 2024款 44mm ',
        'J23':'Watch SE 2024款 44mm ',
    }
    watch_fixed = []
    for cat, model, price in all_items:
        if cat == '苹果手表' and (model.startswith('GPS款') or model.startswith('蜂窝版') or model.startswith('蜂窝款')):
            # 在整个型号字符串中搜索已知的型号代码
            found_prefix = ''
            for code, prefix in WATCH_PREFIX_MAP.items():
                if code in model:
                    found_prefix = prefix
                    break
            if found_prefix and not model.startswith(tuple('S11 S10 S9 Watch'.split())):
                model = found_prefix + model
        watch_fixed.append((cat, model, price))
    all_items = watch_fixed

    # === 清理列拼接导致的错误分类 ===
    def fix_wrong_classification(cat, model, price):
        """修正因多列表格跨列拼接导致的分类错误"""
        # FreeBus/FreeBuds耳机前面有MacBook Pro等笔记本表头
        if cat == '苹果笔记本' and any(kw in model.lower() for kw in ['freebus', 'freebuds', 'freebud']):
            # 去掉前面混入的表头文字
            m = re.sub(r'^.*?(FreeBus|FreeBuds|Freebud)', r'\1', model, flags=re.IGNORECASE)
            return ('华为耳机', m, price)
        # S9/S10/S11/SE3等苹果手表表头拼接了手机型号
        if cat == '华为手机' and re.match(r'S[0-9]+\s+\d+MM\s*表盘', model):
            return ('苹果手表', model, price)
        if cat == 'vivo手机' and re.match(r'(?i)(iQOO\s+)?(?:VIVO\s+)?Pad[0-9]', model):
            return ('vivo平板', model, price)
        return (cat, model, price)
    
    fixed_items = []
    for cat, model, price in all_items:
        cat, model, price = fix_wrong_classification(cat, model, price)
        fixed_items.append((cat, model, price))
    all_items = fixed_items

    # === 清理列拼接：VIVO型号中去掉混杂的OPPO/Find N/Reno内容，反之亦然 ===
    def strip_adjacent_column(model, cat):
        """在多列表格中，去掉相邻列混入的文本"""
        if cat == 'vivo手机':
            # 去掉"Find N"、"Reno"、"一加"等OPPO关键词及其后面的内容
            m = re.split(r'\s+(?:Find\s*N\d*|Reno\d*[A-Za-z]*|一加|OnePlus|Ace\d*)', model, maxsplit=1, flags=re.IGNORECASE)
            if len(m) > 1:
                return m[0].strip()
        if cat == 'OPPO手机':
            # 去掉"X Fold"、"X300"、"X200"、"iQOO"等VIVO关键词及其后面的内容
            m = re.split(r'\s+(?:X\s*Fold\d*|X300|X200|iQOO|vivo|Vivo)', model, maxsplit=1, flags=re.IGNORECASE)
            if len(m) > 1:
                return m[0].strip()
        if cat == '小米手机':
            # 去掉混杂的华为笔记本身份
            m = re.split(r'\s+(?:MateBook|I5-|I7-|Ultra[579])', model, maxsplit=1)
            if len(m) > 1:
                return m[0].strip()
        return model
    
    cleaned_items = []
    for cat, model, price in all_items:
        model = strip_adjacent_column(model, cat)
        cleaned_items.append((cat, model, price))
    all_items = cleaned_items

    # === 华为MateBook前缀补充 ===
    HUAWEI_NOTEBOOK_PREFIX_MAP = {
        # Matebook E 2023款 12.6寸 — I5-1230U / I7-1260U（带键盘）
        'I5-1230U': 'Matebook E 2023款 12.6寸 ',
        'I7-1260U': 'Matebook E 2023款 12.6寸 ',
        # Matebook GT14 14寸 — Ultra5 / Ultra7 / Ultra9
        'Ultra5': 'Matebook GT14 14寸 ',
        'Ultra7': 'Matebook GT14 14寸 ',
        'Ultra9': 'Matebook GT14 14寸 ',
        # Matebook 14S 14.2寸 — I5-13500H / I7-13700H / I9-13900H
        'I5-13500H': 'Matebook 14S 14.2寸 ',
        'I7-13700H': 'Matebook 14S 14.2寸 ',
        'I9-13900H': 'Matebook 14S 14.2寸 ',
        # Matebook D14SE 14寸 — I5-13420H / I5-1240P
    'I5-13420H': 'Matebook D14SE 14寸 ',
    '15-13420H': 'Matebook D14SE 14寸 ',
        'I5-1240P': 'Matebook D14SE 14寸 ',
        '15-12450H': 'Matebook D14SE 14寸 ',
        '15-13500H': 'Matebook 14S 14.2寸 ',
        # 旧版通用（无具体型号匹配时保留）
        'I5-': 'MateBook ', 'I7-': 'MateBook ', 'I9-': 'MateBook ',
        '15-': 'MateBook ',
    }
    huawei_fixed = []
    for cat, model, price in all_items:
        if cat == '华为笔记本':
            first_word = model.split()[0] if model.split() else model
            # 检查是否以I5-/I7-/Ultra5/Ultra7/Ultra9开头（这些是MateBook系列但OCR没扫到前缀）
            for prefix_key, prefix_val in HUAWEI_NOTEBOOK_PREFIX_MAP.items():
                if first_word.startswith(prefix_key) or model.startswith(prefix_key):
                    model = prefix_val + model
                    break
            # 已有的 MateBook 前缀不重复加
        huawei_fixed.append((cat, model, price))
    all_items = huawei_fixed
    MACBOOK_PREFIX_MAP = {
        # MacBook Neo 全系列
        'FA4':'MacBook Neo ', 'FH4':'MacBook Neo ', 'FN4':'MacBook Neo ', 'FK4':'MacBook Neo ',
        'FD4':'MacBook Neo ', 'FF4':'MacBook Neo ', 'FC4':'MacBook Neo ',
        'FJ4':'MacBook Neo ', 'FE4':'MacBook Neo ', 'FG4':'MacBook Neo ',
        # MacBook Air M5/M4 13寸
        'HE4':'MacBook Air ', 'HA4':'MacBook Air ', 'HF4':'MacBook Air ',
        'HC4':'MacBook Air ', 'HG4':'MacBook Air ', 'HD4':'MacBook Air ',
        'H74':'MacBook Air ', 'HH4':'MacBook Air ', 'H84':'MacBook Air ',
        'HJ4':'MacBook Air ', 'HK4':'MacBook Air ',
        # MacBook Air M5 15寸
        'VH4':'MacBook Air ', 'VD4':'MacBook Air ', 'VK4':'MacBook Air ',
        'VQ4':'MacBook Air ', 'VE4':'MacBook Air ', 'VA4':'MacBook Air ',
        'VT4':'MacBook Air ', 'VN4':'MacBook Air ', 'VF4':'MacBook Air ',
        'VC4':'MacBook Air ', 'V94':'MacBook Air ',
        # MacBook Air M4 13寸（数字/字母代码）
        '123':'MacBook Air M4 13寸 ', 'OY3':'MacBook Air M4 13寸 ',
        # MacBook Air M1 库存
        'DA2':'MacBook Air M1 13.3寸 ',
        # MacBook Air M2/M2Pro
        'HE3':'MacBook Pro M2Pro 14.2寸 ', 'HG3':'MacBook Air M2 14.2寸 ',
        'HK3':'MacBook Air M2 14.2寸 ', 'W93':'MacBook Pro M2Pro 16.2寸 ',
        '183':'MacBook Pro M1Pro 16寸 ',
        # MacBook Pro M5 14寸
        '3D4':'MacBook Pro M5 14寸 ', '3E4':'MacBook Pro M5 14寸 ',
        '3F4':'MacBook Pro M5 14寸 ', '3G4':'MacBook Pro M5 14寸 ',
        'E04':'MacBook Pro M5 14寸 ', 'E44':'MacBook Pro M5 14寸 ',
        'E14':'MacBook Pro M5 14寸 ', 'E54':'MacBook Pro M5 14寸 ',
        'E34':'MacBook Pro M5 14寸 ', 'E64':'MacBook Pro M5 14寸 ',
        # MacBook Pro M5Pro 14寸
        'DR4':'MacBook Pro M5Pro 14寸 ', 'DN4':'MacBook Pro M5Pro 14寸 ',
        'LV4':'MacBook Pro M5Pro 14寸 ', 'DT4':'MacBook Pro M5Pro 14寸 ',
        'DP4':'MacBook Pro M5Pro 14寸 ',
        # MacBook Pro M4/M4Pro 14寸
        '2U3':'MacBook Pro M4Pro 14寸 ', '2W3':'MacBook Pro M4 14寸 ',
        '2V3':'MacBook Pro M4 14寸 ', '2X3':'MacBook Pro M4 14寸 ',
        'X04':'MacBook Pro M4 14寸 ', 'X14':'MacBook Pro M4 14寸 ',
        '2H3':'MacBook Pro M4Pro 14寸 ', '2I3':'MacBook Pro M4Pro 16寸 ',
        # MacBook Pro M4Max 16寸
        '303':'MacBook Pro M4Max 16寸 ', '313':'MacBook Pro M4Max 16寸 ',
        # MacBook Pro M3/M3Pro/M3Max 14寸
        'L73':'MacBook Pro M3 14寸 ', '7J3':'MacBook Pro M3 14寸 ',
        '7K3':'MacBook Pro M3 14寸 ',
        'X33':'MacBook Pro M3Pro 14寸 ', 'X63':'MacBook Pro M3Pro 14寸 ',
        'X43':'MacBook Pro M3Pro 14寸 ', 'X73':'MacBook Pro M3Pro 14寸 ',
        'X53':'MacBook Pro M3Max 14寸 ', 'X83':'MacBook Pro M3Max 14寸 ',
        # MacBook Pro M2Max 16寸
        'WE3':'MacBook Pro M2Max 16寸 ', 'WA3':'MacBook Pro M2Max 16寸 ',
        'HU3':'MacBook Pro M2Max 16寸 ',
        # Mac mini
        'YT4':'Mac mini M4 ', 'X44':'Mac mini M4Pro ',
        '9D3':'Mac mini M4 16G 256G ', '9E3':'Mac mini M4 16G 512G ',
        # iMac
        'UC3':'iMac M4 24寸 ', 'UE3':'iMac M4 24寸 ',
    }
    mac_fixed = []
    for cat, model, price in all_items:
        if cat == '苹果笔记本':
            first_word = model.split()[0] if model.split() else model
            prefix = MACBOOK_PREFIX_MAP.get(first_word, '')
            if prefix:
                model = prefix + model
        mac_fixed.append((cat, model, price))
    all_items = mac_fixed
    
    cat_counts = defaultdict(int)
    for cat, model, price in all_items:
        cat_counts[cat] += 1
    print("\n修正后:")
    for cat, cnt in sorted(cat_counts.items(), key=lambda x: -x[1]):
        print(f"  {cat}: {cnt}")
    
    phone_cats = ['苹果手机', '华为手机', '荣耀手机', 'vivo手机', 'iQOO手机', 'OPPO手机', '小米手机',
                  '努比亚手机', '三星手机', '一加手机', '真我手机']
    pad_cats = ['苹果平板', '荣耀平板', '华为平板', 'vivo平板', 'OPPO平板', 'IQOO平板', '一加平板',
                '苹果手表', '华为手表', '小天才手表', '华为儿童手表']
    pc_cats = ['苹果笔记本', '华为笔记本', '苹果配件', '华为耳机', '三星耳机']
    
    phone_items = [(c,m,p) for c,m,p in all_items if c in phone_cats]
    pad_items = [(c,m,p) for c,m,p in all_items if c in pad_cats]
    pc_items = [(c,m,p) for c,m,p in all_items if c in pc_cats]
    other_items = [(c,m,p) for c,m,p in all_items if c not in phone_cats and c not in pad_cats and c not in pc_cats]
    
    print(f"\n页面分配: phone:{len(phone_items)}  pad:{len(pad_items)}  pc:{len(pc_items)}  未分类:{len(other_items)}")
    
    if other_items:
        print("\n未分类样本:")
        prefixes = Counter()
        for c,m,p in other_items:
            first_word = m.split()[0] if m.split() else m
            prefixes[first_word] += 1
        for word, cnt in prefixes.most_common(20):
            print(f"  {word}: {cnt}")
    
    html_phone, n1 = generate_html(phone_items, '手机报价', phone_cats)
    html_pad, n2 = generate_html(pad_items, '平板·手表报价', pad_cats)
    html_pc, n3 = generate_html(pc_items, '电脑·配件报价', pc_cats)
    
    with open(f'{WORKDIR}/phone.html', 'w', encoding='utf-8') as f:
        f.write(html_phone)
    with open(f'{WORKDIR}/pad.html', 'w', encoding='utf-8') as f:
        f.write(html_pad)
    with open(f'{WORKDIR}/pc.html', 'w', encoding='utf-8') as f:
        f.write(html_pc)
    
    print(f"\n✅ 已生成3个HTML页面: phone.html:{n1}  pad.html:{n2}  pc.html:{n3}  总计:{n1+n2+n3}")

if __name__ == '__main__':
    main()
