#!/usr/bin/env python3
"""Build an Obsidian vault from NLM (Nguyên Liệu Mới) data."""

import os, re, shutil, json
from pathlib import Path

# --- CONFIG ---
NLM_ROOT = Path(r"C:\antigra-DS\CLAW_LAM_VIEC\Nghien cuu\Nguyen-Lieu-Moi (NLM)")
VAULT_DIR = Path(r"C:\antigra-DS\CLAW_LAM_VIEC\Nghien cuu\Obsidian-NLM-Vault")

# Files to include (relative to NLM_ROOT): only .md files that are actual content
MD_FILES = {
    "WIKI_NLM.md": {"title": "WIKI Nguyên Liệu Mới", "tags": ["nlm", "wiki", "tổng-hợp"], "supplier": "all"},
    "AIREX/BÁO CÁO TỔNG HỢP NGUYÊN LIỆU MỚI AIREX.md": {
        "title": "Báo cáo tổng hợp — AIREX 920", "tags": ["nlm", "airex", "phụ-gia", "phá-bọt", "uv"], "supplier": "AIREX"},
    "BOSSIN/BÁO CÁO TỔNG HỢP NGUYÊN LIỆU MỚI BOSSIN.md": {
        "title": "Báo cáo tổng hợp — BOSSIN DPHA", "tags": ["nlm", "bossin", "monomer", "uv", "dpha"], "supplier": "BOSSIN"},
    "KETIAN/BÁO CÁO TỔNG HỢP NGUYÊN LIỆU MỚI KETIAN.md": {
        "title": "Báo cáo tổng hợp — KETIAN 4212/2202", "tags": ["nlm", "ketian", "nhựa-uv", "epoxy-acrylate", "polyester-acrylate"], "supplier": "KETIAN"},
    "WANGSAN/BÁO CÁO TỔNG HỢP KẾT QUẢ THỬ NGHIỆM NGUYÊN LIỆU MỚI WANGSAN.md": {
        "title": "Báo cáo tổng hợp — WANGSAN", "tags": ["nlm", "wangsan", "monomer", "uv"], "supplier": "WANGSAN"},
    "SUZE/DS-1095_TDS.md": {
        "title": "DS-1095 — Nhựa Acrylic Nhiệt Dẻo (SUZE)", "tags": ["nlm", "suze", "nhựa-acrylic", "nc", "pu"], "supplier": "SUZE"},
}

# Entity cross-reference: {entity_lower: display_name, wikilink_target, category}
ENTITIES = {
    "airex":        ("AIREX", "AIREX", "nhà-cung-cấp"),
    "airex 920":    ("Airex 920", "AIREX", "nguyên-liệu"),
    "bossin":       ("BOSSIN", "BOSSIN", "nhà-cung-cấp"),
    "dpha-90":      ("DPHA-90", "BOSSIN", "nguyên-liệu"),
    "dpha-80":      ("DPHA-80", "BOSSIN", "nguyên-liệu"),
    "ketian":       ("KETIAN", "KETIAN", "nhà-cung-cấp"),
    "4212":         ("4212", "KETIAN", "nguyên-liệu"),
    "2202":         ("2202", "KETIAN", "nguyên-liệu"),
    "wangsan":      ("WANGSAN", "WANGSAN", "nhà-cung-cấp"),
    "sw107":        ("SW107", "WANGSAN", "nguyên-liệu"),
    "sw515":        ("SW515", "WANGSAN", "nguyên-liệu"),
    "sw525":        ("SW525", "WANGSAN", "nguyên-liệu"),
    "suze":         ("SUZE", "SUZE", "nhà-cung-cấp"),
    "ds-1095":      ("DS-1095", "SUZE", "nguyên-liệu"),
    "b-113":        ("B-113", "B-113", "nguyên-liệu-tham-chiếu"),
    "w-522":        ("W-522", "W-522", "nguyên-liệu-tham-chiếu"),
    "byk 1798":     ("BYK 1798", "BYK-1798", "nguyên-liệu-tham-chiếu"),
    "trần vũ linh": ("Trần Vũ Linh", "Trần Vũ Linh", "nhân-viên"),
}

# Wikilink targets file -> entity mapping
FILE_ENTITIES = {
    "WIKI_NLM.md": ["AIREX", "BOSSIN", "KETIAN", "WANGSAN", "SUZE",
                    "Airex 920", "DPHA-90", "DPHA-80", "4212", "2202",
                    "SW107", "SW515", "SW525", "DS-1095"],
    "AIREX/...AIREX.md": ["Airex 920", "AIREX", "BYK 1798", "Trần Vũ Linh", "B-113"],
    "BOSSIN/...BOSSIN.md": ["BOSSIN", "DPHA-90", "DPHA-80", "Airex 920"],
    "KETIAN/...KETIAN.md": ["KETIAN", "4212", "2202", "B-113", "W-522", "Trần Vũ Linh", "TPGDA", "HDDA"],
    "WANGSAN/...WANGSAN.md": ["WANGSAN", "SW107", "SW515", "SW525"],
    "SUZE/...DS-1095_TDS.md": ["SUZE", "DS-1095", "B-113", "W-522"],
}

# --- HELPER ---
def slugify(name):
    return re.sub(r'[^a-zA-Z0-9\u00C0-\u024F\u1e00-\u1eff\u30-\u39\-]', '-', name).strip('-').lower()

def supplier_note_name(supplier):
    """Get the wikilink anchor for a supplier's report."""
    mapping = {
        "AIREX": "AIREX",
        "BOSSIN": "BOSSIN",
        "KETIAN": "KETIAN",
        "WANGSAN": "WANGSAN",
        "SUZE": "SUZE",
    }
    return mapping.get(supplier, supplier)

def get_content_based_tags(content, rel_path_str):
    """Derive tags from content analysis."""
    tags = set()
    content_lower = content.lower()
    if "uv" in content_lower or "monomer" in content_lower: tags.add("uv")
    if "phá bọt" in content_lower or "defoamer" in content_lower: tags.add("phá-bọt")
    if "acrylic" in content_lower: tags.add("nhựa-acrylic")
    if "epoxy" in content_lower: tags.add("epoxy")
    if "nc" in content_lower: tags.add("nc")
    if "pu" in content_lower or "2k" in content_lower: tags.add("pu")
    if "sealer" in content_lower: tags.add("sealer")
    if "tds" in content_lower: tags.add("tds")
    return tags

def extract_h1(content):
    m = re.search(r'^#\s+(.+)$', content, re.MULTILINE)
    return m.group(1).strip() if m else None

def add_frontmatter(content, title, tags):
    """Add YAML frontmatter if not present."""
    if content.startswith("---"):
        return content  # already has frontmatter
    
    tag_str = "\n" + "\n".join(f"  - {t}" for t in sorted(tags)) if tags else "  []"
    
    fm = f"""---
title: "{title}"
tags:
{tag_str}
created: 2026-07-25
---
"""
    return fm + content

def add_wikilinks(content, entity_wikilinks):
    """Add wikilinks section at the bottom if not already present."""
    # Check if already has wikilinks section
    if "## Liên kết" in content or "## 🔗 Liên kết" in content:
        return content
    
    if not entity_wikilinks:
        return content
    
    links = sorted(set(entity_wikilinks))
    link_lines = "\n".join(f"- [[{l}]]" for l in links)
    
    wikilink_section = f"""
---
## 🔗 Liên kết

{link_lines}
"""
    return content.rstrip() + wikilink_section

def find_entity_links(content, known_entities):
    """Scan content for entity mentions and return list of wikilink targets."""
    found = []
    content_lower = content.lower()
    for entity_key, (display_name, target, _) in known_entities.items():
        # Check if entity name appears in content (word boundary insensitive)
        pattern = re.compile(re.escape(entity_key), re.IGNORECASE)
        if pattern.search(content_lower):
            if target not in found:
                found.append(target)
    return found

def copy_and_process():
    """Main build function."""
    # Clean and create vault directory
    if VAULT_DIR.exists():
        shutil.rmtree(VAULT_DIR)
    VAULT_DIR.mkdir(parents=True)
    
    # Create supplier directories in vault
    for rel_path in MD_FILES:
        dir_path = VAULT_DIR / os.path.dirname(rel_path)
        if dir_path != VAULT_DIR:
            dir_path.mkdir(parents=True, exist_ok=True)
    
    # Create .obsidian config
    obsidian_dir = VAULT_DIR / ".obsidian"
    obsidian_dir.mkdir(exist_ok=True)
    
    # .obsidian/app.json
    app_config = {
        "theme": "moonstone",
        "baseFontSize": 15,
        "showLineNumber": True,
        "spellcheck": False,
        "readableLineLength": True,
        "strictLineBreaks": False,
        "autoConvertHtml": True,
    }
    (obsidian_dir / "app.json").write_text(json.dumps(app_config, ensure_ascii=False, indent=2), encoding="utf-8")
    
    # .obsidian/core-plugins.json
    core_plugins = [
        "file-explorer",
        "global-search",
        "switcher",
        "graph",
        "backlink",
        "canvas",
        "tag-pane",
        "page-preview",
        "note-composer",
        "command-palette",
        "editor-status",
        "outline",
        "word-count",
        "file-recovery"
    ]
    (obsidian_dir / "core-plugins.json").write_text(json.dumps(core_plugins, ensure_ascii=False, indent=2), encoding="utf-8")
    
    # .obsidian/graph.json
    graph_config = {
        "collapse-filter": False,
        "search": "",
        "showTags": True,
        "showAttachments": False,
        "hideUnresolved": False,
        "showOrphans": False,
        "collapse-color-groups": False,
        "colorGroups": [],
        "collapse-display": False,
        "showArrow": True,
        "textFadeMultiplier": 0,
        "nodeSizeMultiplier": 1,
        "lineSizeMultiplier": 1,
        "collapse-forces": False,
        "centerStrength": 0.518,
        "repelStrength": 10,
        "linkStrength": 1,
        "linkDistance": 250,
        "scale": 1,
        "close": False
    }
    (obsidian_dir / "graph.json").write_text(json.dumps(graph_config, ensure_ascii=False, indent=2), encoding="utf-8")
    
    # .obsidian/community-plugins.json
    (obsidian_dir / "community-plugins.json").write_text("[]\n", encoding="utf-8")
    
    # Process each file
    processed = []
    for rel_path, meta in MD_FILES.items():
        src = NLM_ROOT / rel_path
        if not src.exists():
            print(f"  ⚠️  Missing: {rel_path}")
            continue
        
        content = src.read_text(encoding="utf-8")
        
        # Get title
        h1 = extract_h1(content)
        title = meta["title"]
        
        # Combine predefined + content-based tags
        tags = set(meta["tags"])
        tags.update(get_content_based_tags(content, rel_path))
        
        # Add frontmatter
        enriched = add_frontmatter(content, title, tags)
        
        # Find entity mentions -> wikilinks
        entity_links = find_entity_links(enriched, ENTITIES)
        
        # Add wikilinks section
        enriched = add_wikilinks(enriched, entity_links)
        
        # Write to vault
        dst = VAULT_DIR / rel_path
        dst.write_text(enriched, encoding="utf-8")
        processed.append((rel_path, len(entity_links), sorted(entity_links)))
        print(f"  ✅ {rel_path} ({len(entity_links)} wikilinks)")
    
    # --- CREATE SUPPLEMENTARY ENTITY NOTES ---
    # Create stub notes for key referenced entities that don't have their own file
    entity_notes = {
        "BYK-1798.md": {
            "title": "BYK 1798 — Phụ gia phá bọt Silicone",
            "content": """# BYK 1798 — Phụ gia phá bọt Silicone

> **Nguyên liệu tham chiếu** — Đối chứng cho thử nghiệm [[AIREX]]

| Thông tin | Giá trị |
|:----------|:--------|
| **Nhà cung cấp** | BYK (BYK-Chemie, Đức) |
| **Loại** | Phụ gia phá bọt Silicone |
| **Hàm lượng hoạt chất** | 10% |
| **Dung môi** | Butylglycol/Ethylhexanol/White Spirit (6/2/1) |
| **Tỷ trọng** | 0.88 g/ml |
| **Ghi chú** | Chứa C6 F13 fluorotelomers |

**Đặc điểm:**
- Phá bọt hiệu quả trong hệ nước và UV
- Có chứa silicone → khó tái sơn/dán keo
- Chứa fluorotelomer → lo ngại về môi trường

**So sánh:** [[AIREX]] Airex 920 được thử nghiệm thay thế BYK 1798 (silicone-free, không fluorotelomer).
"""
        },
        "B-113.md": {
            "title": "B-113 — Nhựa Epoxy Acrylate (Bossin)",
            "content": """# B-113 — Nhựa Epoxy Acrylate (Bossin)

> **Nguyên liệu tham chiếu** — Đối chứng cho [[KETIAN]] 4212

| Thông tin | Giá trị |
|:----------|:--------|
| **Nhà cung cấp** | Bossin (Guangdong Bossin) |
| **Loại** | Bisphenol A epoxy acrylate |
| **Hàm lượng rắn** | 100% |
| **Độ nhớt** | 15.000-25.000 cps |
| **Chức năng** | 2 |
| **Tỷ trọng** | 1.15±0.02 g/cm³ |
| **Pha loãng** | 20% TPGDA |

**So sánh:** [[KETIAN]] 4212 (độ nhớt 25.000-35.000 cps) thử thay thế B-113.
"""
        },
        "W-522.md": {
            "title": "W-522 — Nhựa Polyester Acrylate (Bossin)",
            "content": """# W-522 — Nhựa Polyester Acrylate (Bossin)

> **Nguyên liệu tham chiếu** — Đối chứng cho [[KETIAN]] 2202

| Thông tin | Giá trị |
|:----------|:--------|
| **Nhà cung cấp** | Bossin (Guangdong Bossin) |
| **Loại** | Polyester acrylate |
| **Hàm lượng rắn** | 100% |
| **Độ nhớt** | 25.000-45.000 cps |
| **Chức năng** | 2 |
| **Tỷ trọng** | 1.33±0.02 g/cm³ |

**So sánh:** [[KETIAN]] 2202 (độ nhớt 25.000-35.000 cps) thử thay thế W-522.
"""
        },
        "Trần Vũ Linh.md": {
            "title": "Trần Vũ Linh — Nhân viên Lab R&D",
            "content": """# Trần Vũ Linh

> **Nhân viên phòng Lab R&D** — Thực hiện các thử nghiệm nguyên liệu mới

**Các thử nghiệm đã thực hiện:**
- [[AIREX]] — Thử nghiệm Airex 920 (02-06/07/2026)
- [[KETIAN]] — Thử nghiệm 4212/2202 (07-08/07/2026)
"""
        },
        "TPGDA.md": {
            "title": "TPGDA — Tripropylene Glycol Diacrylate",
            "content": """# TPGDA — Tripropylene Glycol Diacrylate

> **Monomer pha loãng** trong hệ UV

Sử dụng làm dung môi pha loãng cho nhựa epoxy acrylate trong các thử nghiệm [[KETIAN]].
"""
        },
        "HDDA.md": {
            "title": "HDDA — Hexanediol Diacrylate",
            "content": """# HDDA — Hexanediol Diacrylate

> **Monomer pha loãng** trong hệ UV

Sử dụng làm dung môi pha loãng cho nhựa polyester acrylate trong các thử nghiệm [[KETIAN]].
"""
        },
    }
    
    for filename, note in entity_notes.items():
        dst = VAULT_DIR / filename
        dst.write_text(note["content"], encoding="utf-8")
        print(f"  ✅ {filename} (entity stub)")
    
    # --- CREATE MOC FILES ---
    # Master MOC
    master_moc = """---
title: "MOC — Nguyên Liệu Mới (NLM)"
tags:
  - moc
  - nlm
  - tổng-hợp
created: 2026-07-25
---

# 🗺️ MOC: Nguyên Liệu Mới (NLM)

> **Trung tâm điều hướng** — Kết nối toàn bộ dữ liệu nghiên cứu nguyên liệu đầu vào thay thế

## 📊 Thống kê

| Chỉ tiêu | Giá trị |
|:---------|:-------:|
| Số nhà cung cấp đang theo dõi | 5 |
| Số nguyên liệu đã thử nghiệm | 4 |
| Số nguyên liệu đang chờ | 4 |
| Người thử nghiệm chính | [[Trần Vũ Linh]] |

## 🏭 Nhà cung cấp

| NCC | Nguyên liệu | Tình trạng | 
|:----|:------------|:----------:|
| [[AIREX]] | [[Airex 920]] — Phụ gia phá bọt | ✅ Đã thử nghiệm |
| [[BOSSIN]] | [[DPHA-90]], [[DPHA-80]] — Monomer UV | 📄 Đã có TDS |
| [[KETIAN]] | [[4212]], [[2202]] — Nhựa UV | ✅ Đã thử nghiệm |
| [[WANGSAN]] | [[SW107]], [[SW515]], [[SW525]] — Monomer UV | 📄 Đang tổng hợp |
| [[SUZE]] | [[DS-1095]] — Nhựa Acrylic | ✅ Mới cập nhật |

## 🔬 Nguyên liệu tham chiếu (đối chứng)

| Nguyên liệu gốc | NCC gốc | Thử nghiệm thay thế |
|:-----------------|:--------|:-------------------|
| [[BYK-1798]] (Phá bọt Silicone) | BYK | [[AIREX]] → Airex 920 |
| [[B-113]] (Epoxy Acrylate) | Bossin | [[KETIAN]] → 4212 |
| [[W-522]] (Polyester Acrylate) | Bossin | [[KETIAN]] → 2202 |

## 📂 Wiki

- [[WIKI_NLM]] — Wiki tổng hợp tất cả nguyên liệu mới
"""
    moc_file = VAULT_DIR / "MOC-NLM.md"
    moc_file.write_text(master_moc, encoding="utf-8")
    print("  ✅ MOC-NLM.md (Master MOC)")
    
    # Supplier MOCs
    supplier_mocs = {
        "AIREX": ("AIREX", "AIREX 920 — Phụ gia phá bọt thay thế BYK 1798", ["AIREX", "Airex 920", "BYK-1798", "phụ-gia", "phá-bọt"]),
        "BOSSIN": ("BOSSIN", "DPHA-90 / DPHA-80 — Monomer UV đa chức", ["BOSSIN", "DPHA-90", "DPHA-80", "monomer", "uv"]),
        "KETIAN": ("KETIAN", "4212 / 2202 — Nhựa UV thay thế B-113 / W-522", ["KETIAN", "4212", "2202", "B-113", "W-522", "nhựa-uv"]),
        "WANGSAN": ("WANGSAN", "SW107 / SW515 / SW525 — Monomer UV", ["WANGSAN", "SW107", "SW515", "SW525", "monomer", "uv"]),
        "SUZE": ("SUZE", "DS-1095 — Nhựa Acrylic Nhiệt Dẻo", ["SUZE", "DS-1095", "nhựa-acrylic", "tds"]),
    }
    
    for supplier, (short_name, desc, link_tags) in supplier_mocs.items():
        # Find files for this supplier
        supplier_files = [rel for rel, meta in MD_FILES.items() if meta.get("supplier") == supplier]
        # Find entity stubs for this supplier's materials
        entity_stubs = []
        for ent_key, (display, target, cat) in ENTITIES.items():
            if cat == "nguyên-liệu" and target == supplier:
                entity_stubs.append(display)
            elif cat == "nguyên-liệu-tham-chiếu":
                pass  # don't include
            elif cat == "nhà-cung-cấp" and display == supplier:
                pass  # self
        
        file_links = "\n".join(f"- [[{os.path.splitext(os.path.basename(rel))[0]}]]" for rel in supplier_files if rel)
        entity_links = "\n".join(f"- [[{e}]]" for e in sorted(entity_stubs))
        
        moc_content = f"""---
title: "MOC — {supplier}"
tags:
  - moc
  - nlm
  - "{short_name}"
created: 2026-07-25
---

# 🗺️ MOC: {supplier}

> {desc}

## 📄 Báo cáo

{file_links}

## 🔗 Nguyên liệu liên quan

{entity_links if entity_links else "_Không có dữ liệu_"}

## 🏷️ Tags chính
`#nlm` `#{short_name.lower().replace(' ', '-')}`
"""
        moc_path = VAULT_DIR / f"MOC-{supplier}.md"
        moc_path.write_text(moc_content, encoding="utf-8")
        print(f"  ✅ MOC-{supplier}.md")
    
    # --- REPORT ---
    print(f"\n{'='*60}")
    print(f"  📊 BUILD COMPLETE")
    print(f"  Vault: {VAULT_DIR}")
    total_files = len(MD_FILES) + len(entity_notes) + 1 + len(supplier_mocs)
    print(f"  Total notes: {total_files}")
    print(f"  - Original reports: {len(MD_FILES)}")
    print(f"  - Entity stubs: {len(entity_notes)}")
    print(f"  - MOC files: {1 + len(supplier_mocs)}")
    print(f"{'='*60}")

if __name__ == "__main__":
    copy_and_process()
