#!/usr/bin/env python3
"""
Publish 20 DAS articles to dasindonesia.com via WordPress REST API.
Each article gets its own featured image (1000x567 webp) + Yoast SEO meta.
Requires: pip install requests (Pillow for nothing here; images already webp).
"""
import requests
from requests.auth import HTTPBasicAuth
import json, re, html, os, time, sys

WP_URL = "https://dasindonesia.com/wp-json/wp/v2"
USER = "bambangbot"
APP_PASSWORD = "VzXR 72KF NJWn XxHI MhJN B9Hs"
AUTH = HTTPBasicAuth(USER, APP_PASSWORD)

# Shared session with strict timeouts + retry
_s = requests.Session()
_s.auth = AUTH
_ad = requests.adapters.HTTPAdapter(max_retries=2)
_s.mount('https://', _ad)

def api(method, url, **kw):
    kw.setdefault('timeout', 40)
    return _s.request(method, url, **kw)

BASE = "/home/mantapman/.hermes/profiles/atun/workspace/artikel-das-20"
IMG = os.path.join(BASE, "images")

# Category mapping per article stub
CATS = {
    "artikel-01": [1, 623],   # TOYOTA + Tips Teknis (bengkel premium, Alphard-driven)
    "artikel-02": [1, 623],   # TOYOTA + Tips Teknis (mobil mewah)
    "artikel-03": [1, 623],   # TOYOTA + Tips (spesialis overhaul umum)
    "artikel-04": [1, 623],   # TOYOTA + Tips (MPV/SUV - Alphard/Innova)
    "artikel-05": [1],        # TOYOTA (Alphard)
    "artikel-06": [1, 623],   # TOYOTA + Tips (biaya overhaul Alphard)
    "artikel-07": [1, 623],   # TOYOTA + Tips (servis rutin Alphard)
    "artikel-08": [1, 623],   # TOYOTA + Tips (masalah mesin Alphard)
    "artikel-09": [7],        # HONDA
    "artikel-10": [7, 623],   # HONDA + Tips
    "artikel-11": [7, 623],   # HONDA + Tips
    "artikel-12": [7, 623],   # HONDA + Tips (transmisi)
    "artikel-13": [7, 623],   # HONDA + Tips (turbo)
    "artikel-14": [7, 623],   # HONDA + Tips (gejala overhaul)
    "artikel-15": [219],      # NISSAN
    "artikel-16": [219, 623], # NISSAN + Tips
    "artikel-17": [219, 623], # NISSAN + Tips
    "artikel-18": [219, 623], # NISSAN + Tips (bekas)
    "artikel-19": [1, 623],   # TOYOTA + Tips (multi-merek Jepang)
    "artikel-20": [1, 623],   # TOYOTA + Tips (tanda mobil mewah)
}

# Known-useful tags (id: name) — we reuse ones we know; create for others
PRESET_TAGS = {
    "overhaul": 633,          # overhaul mesin
    "overhaulmesin": 554,     # overhaul mesin mobil
    "bengkeloverhaul": 503,   # overhaul mobil
    "perawatan": 604,
    "perawatanmobil": 622,
    "tips": 623,
}

def find_or_create_tag(name, slug=None):
    if not slug:
        slug = name.lower().replace(' ', '-')
    r = api('GET', f"{WP_URL}/tags", params={"search": name})
    if r.status_code == 200:
        for t in r.json():
            if t['name'].lower() == name.lower():
                return t['id']
    r = api('POST', f"{WP_URL}/tags", json={"name": name, "slug": slug})
    if r.status_code in (200, 201):
        print(f"  🏷️ Created tag '{name}' ({r.json()['id']})")
        return r.json()['id']
    return None

def upload_image(filepath, alt):
    fn = os.path.basename(filepath)
    with open(filepath, 'rb') as f:
        files = {'file': (fn, f, 'image/webp')}
        data = {'alt': alt, 'caption': alt}
        r = _s.post(f"{WP_URL}/media", files=files, data=data, timeout=90)
    if r.status_code in (200, 201):
        j = r.json()
        print(f"  🖼️ Img ID {j['id']}")
        return j['id']
    else:
        print(f"  ⚠️ Img fail HTTP {r.status_code}: {r.text[:200]}")
        return None

def md_to_wp(md_text):
    """Convert markdown body to WordPress HTML blocks."""
    parts = []
    lines = md_text.split('\n')
    i = 0
    while i < len(lines):
        line = lines[i]
        if not line.strip():
            i += 1; continue
        if line.startswith('## '):
            parts.append(f'<!-- wp:heading --><h2>{html.escape(line[3:].strip())}</h2><!-- /wp:heading -->')
        elif line.startswith('### '):
            parts.append(f'<!-- wp:heading {{"level":3}} --><h3>{html.escape(line[4:].strip())}</h3><!-- /wp:heading -->')
        elif line.startswith('#### '):
            parts.append(f'<!-- wp:heading {{"level":4}} --><h4>{html.escape(line[5:].strip())}</h4><!-- /wp:heading -->')
        elif line.strip().startswith('- ') or line.strip().startswith('* '):
            items = []
            while i < len(lines) and (lines[i].strip().startswith('- ') or lines[i].strip().startswith('* ')):
                raw = lines[i].strip()[2:]
                raw = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', raw)
                # checkbox
                m = re.match(r'\[( |x|X)\] (.+)', raw)
                if m:
                    chk = 'checked' if m.group(1).lower() == 'x' else ''
                    items.append(f'<li><input type="checkbox" {chk} disabled=""> {m.group(2)}</li>')
                else:
                    items.append(f'<li>{raw}</li>')
                i += 1
            parts.append(f'<!-- wp:list --><ul>{"".join(items)}</ul><!-- /wp:list -->')
            continue
        elif re.match(r'^\d+[\.\)] ', line.strip()):
            items = []
            while i < len(lines) and re.match(r'^\d+[\.\)] ', lines[i].strip()):
                raw = re.sub(r'^\d+[\.\)] ', '', lines[i].strip())
                raw = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', raw)
                items.append(f'<li>{raw}</li>')
                i += 1
            parts.append(f'<!-- wp:list {{"ordered":true}} --><ol>{"".join(items)}</ol><!-- /wp:list -->')
            continue
        elif line.strip().startswith('|') and '|' in line:
            rows = []
            while i < len(lines) and lines[i].strip().startswith('|') and '|' in lines[i]:
                cells = [c.strip() for c in lines[i].strip().split('|')[1:-1]]
                if all(re.match(r'^-+$', c) for c in cells):
                    i += 1; continue
                rows.append(cells)
                i += 1
            if rows:
                t = '<figure class="wp-block-table"><table><thead><tr>'
                for c in rows[0]: t += f'<th>{c}</th>'
                t += '</tr></thead><tbody>'
                for row in rows[1:]:
                    t += '<tr>'
                    for c in row: t += f'<td>{c}</td>'
                    t += '</tr>'
                t += '</tbody></table></figure>'
                parts.append(f'<!-- wp:table -->{t}<!-- /wp:table -->')
            continue
        elif line.strip() == '---':
            i += 1; continue
        else:
            para = []
            while i < len(lines):
                l = lines[i]
                if (l.startswith('#') or l.strip().startswith('- ') or l.strip().startswith('* ')
                        or re.match(r'^\d+[\.\)] ', l.strip()) or l.strip() == '---'
                        or not l.strip() or l.strip().startswith('|')):
                    break
                para.append(l.strip())
                i += 1
            if para:
                txt = '<br>'.join(para)
                txt = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', txt)
                txt = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', r'<a href="\2">\1</a>', txt)
                parts.append(f'<!-- wp:paragraph --><p>{txt}</p><!-- /wp:paragraph -->')
            continue
        i += 1
    return '\n'.join(parts)

def parse_article(path):
    with open(path, 'r', encoding='utf-8') as f:
        c = f.read()
    m = re.match(r'^# (.+)', c)
    title = m.group(1).strip() if m else "Untitled"
    meta = re.search(r'\*\*Meta Description:\*\*\s*(.+)', c)
    meta_desc = meta.group(1).strip() if meta else ""
    kw = re.search(r'\*\*Keyword Utama:\*\*\s*(.+)', c)
    keyphrase = kw.group(1).strip() if kw else title
    # body = everything after the front-matter block (after --- line following keywords)
    body = c
    body = re.sub(r'\*\*Meta Description:\*\*.+?\n', '', body)
    body = re.sub(r'\*\*Keyword Utama:\*\*.+?\n', '', body)
    body = re.sub(r'\*\*Keyword Sekunder:\*\*.+?\n', '', body)
    # drop the first --- front-matter separator if present right after title block
    body = re.sub(r'^# .+\n', '', body)
    body = re.sub(r'^---\s*\n', '', body, count=1)
    wp = md_to_wp(body)
    slug = re.sub(r'[^\w\s-]', '', title.lower())
    slug = re.sub(r'[-\s]+', '-', slug).strip('-')
    return {'title': title, 'slug': slug, 'meta': meta_desc, 'kw': keyphrase, 'content': wp}

def build_tags(stub, kw, content_lower, meta):
    tags = set()
    low = kw.lower()
    if 'overhaul' in low or 'overhaul' in content_lower:
        tags.add(PRESET_TAGS['overhaul'])
        tags.add(PRESET_TAGS['overhaulmesin'])
    if 'alphard' in low or 'toyota' in low:
        t = find_or_create_tag("Alphard", "alphard")
        if t: tags.add(t)
    if 'honda' in low:
        tags.add(7 if False else None)  # placeholder
    # use tag by brand
    if 'honda' in low or 'honda' in content_lower:
        t = find_or_create_tag("Mobil Honda", "mobil-honda")
        if t: tags.add(t)
        t2 = find_or_create_tag("VTEC", "vtec") if 'vtec' in content_lower else None
        if t2: tags.add(t2)
    if 'nissan' in low or 'nissan' in content_lower:
        t = find_or_create_tag("Mobil Nissan", "mobil-nissan")
        if t: tags.add(t)
        if 'cvt' in content_lower:
            t2 = find_or_create_tag("CVT", "cvt")
            if t2: tags.add(t2)
    if 'mewah' in low or 'premium' in low:
        t = find_or_create_tag("Mobil Mewah", "mobil-mewah")
        if t: tags.add(t)
    if 'servis' in low or 'perawatan' in low or 'servis' in content_lower:
        tags.add(PRESET_TAGS['perawatan'])
        tags.add(PRESET_TAGS['perawatanmobil'])
    tags.add(PRESET_TAGS['tips'])
    return [t for t in tags if t]

def main():
    only = sys.argv[1] if len(sys.argv) > 1 else None  # optional: publish only ONE stub e.g. artikel-05
    # Artikels 01-05 already exist on dasindonesia.com (verified) — skip to avoid duplicates
    SKIP = {'artikel-01','artikel-02','artikel-03','artikel-04','artikel-05'}
    files = sorted([f for f in os.listdir(BASE) if f.endswith('.md') and ('artikel-' + f.split('-')[1]) not in SKIP])
    if only:
        files = [f for f in files if f.startswith(only + '-')]
    print(f"Found {len(files)} .md files to process (skip 01-05 already published)")
    # test conn using a fast endpoint
    r = api('GET', f"{WP_URL}/categories", params={"per_page": 1})
    if r.status_code != 200:
        print("❌ Connection failed", r.status_code, r.text[:200])
        return
    print("✅ Connected to WordPress")
    results = []
    for idx, fn in enumerate(files, 1):
        stub = 'artikel-' + fn.split('-')[1]
        path = os.path.join(BASE, fn)
        art = parse_article(path)
        imgpath = os.path.join(IMG, f"{stub}.webp")
        print(f"\n[{idx}/{len(files)}] {stub}: {art['title'][:60]}", flush=True)
        if not os.path.exists(imgpath):
            print("  ⚠️ Feature image missing:", imgpath)
            fid = None
        else:
            fid = upload_image(imgpath, art['title'])
        cats = CATS.get(stub, [1, 623])
        tags = build_tags(stub, art['kw'], art['content'].lower(), art['meta'])
        data = {
            'title': art['title'],
            'content': art['content'],
            'slug': art['slug'],
            'status': 'publish',
            'categories': cats,
            'tags': tags,
            'excerpt': art['meta'][:155],
            'featured_media': fid,
            'meta': {
                '_yoast_wpseo_title': art['title'],
                '_yoast_wpseo_metadesc': art['meta'][:155],
                '_yoast_wpseo_focuskw': art['kw'],
            }
        }
        r = api('POST', f"{WP_URL}/posts", json=data)
        if r.status_code in (200, 201):
            j = r.json()
            print(f"  ✅ Post {j['id']} — {j.get('link')}", flush=True)
            results.append((stub, art['title'], j['id'], j.get('link'), True))
        else:
            print(f"  ❌ HTTP {r.status_code}: {r.text[:400]}", flush=True)
            results.append((stub, art['title'], None, None, False))
        time.sleep(2)
    print("\n=== SUMMARY ===")
    ok = sum(1 for r in results if r[4])
    print(f"✅ {ok}/{len(results)} published")
    for s, t, pid, link, good in results:
        print(f"  {'✅' if good else '❌'} {s} — {t[:55]}" + (f"  [{pid}]" if pid else ""))

if __name__ == "__main__":
    main()
