#!/usr/bin/env python3
"""
=============================================================
 WordPress Auto-Post Script
 learn-lexicore.bytronex.com
 
 100% FREE: Gemini Flash API + Unsplash API + WordPress REST
 يعمل تلقائياً كل يوم عبر Cron Job
=============================================================
"""

import os
import sys
import json
import random
import base64
import requests
import argparse
from datetime import datetime
from typing import Optional, Tuple

# ── الملفات والمسارات ──────────────────────────────────────
SCRIPT_DIR  = os.path.dirname(os.path.abspath(__file__))
CONFIG_FILE  = os.path.join(SCRIPT_DIR, "config.json")
KEYWORDS_FILE = os.path.join(SCRIPT_DIR, "keywords.txt")
PROGRESS_FILE = os.path.join(SCRIPT_DIR, "progress.json")
LOG_FILE     = os.path.join(SCRIPT_DIR, "auto_post.log")


# ═══════════════════════════════════════════════════════════
# 1. الأدوات المساعدة
# ═══════════════════════════════════════════════════════════

def log(msg: str, level: str = "INFO"):
    """كتابة رسالة في اللوج وعلى الشاشة."""
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    line = f"[{timestamp}] [{level}] {msg}"
    print(line)
    with open(LOG_FILE, "a", encoding="utf-8") as f:
        f.write(line + "\n")


def load_json(path: str) -> dict:
    """تحميل ملف JSON."""
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)


def save_json(path: str, data: dict):
    """حفظ ملف JSON."""
    with open(path, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)


def load_keywords() -> list:
    """تحميل قائمة الكلمات من keywords.txt (تجاهل الأسطر الفارغة والتعليقات)."""
    with open(KEYWORDS_FILE, "r", encoding="utf-8") as f:
        lines = [l.strip() for l in f if l.strip() and not l.startswith("#")]
    return lines


# ═══════════════════════════════════════════════════════════
# 2. اختيار الـ Keyword اليومية
# ═══════════════════════════════════════════════════════════

def pick_next_keyword(keywords: list, progress: dict) -> Tuple[str, int]:
    """
    يختار الـ keyword التالية بالترتيب (لتغطية الكل بالتسلسل).
    عند انتهاء الكل يعيد من البداية.
    """
    last_index = progress.get("last_index", -1)
    next_index = (last_index + 1) % len(keywords)
    return keywords[next_index], next_index


# ═══════════════════════════════════════════════════════════
# 3. توليد المقال بـ Groq (مجاني وسريع)
# ═══════════════════════════════════════════════════════════

def generate_article(cfg: dict, keyword: str, lang: str = "en") -> dict:
    """
    يستدعي Groq API لتوليد مقال HTML كامل.
    يُرجع: {"title": ..., "content": ..., "excerpt": ...}
    """
    api_key = cfg["groq"]["api_key"]
    model   = cfg["groq"].get("model", "llama-3.3-70b-versatile")
    words   = cfg["settings"].get("article_words", 800)
    sections = cfg["settings"].get("article_sections", 4)
    site    = cfg["settings"].get("site_name", "LexiCore")
    site_url = cfg["settings"].get("site_url", "https://learn-lexicore.bytronex.com")

    if lang == "ar":
        prompt = f"""أنت كاتب محتوى خبير في تحسين محركات البحث ومتخصص في تعلم اللغة الإنجليزية للأفراد العسكريين (ALCPT/ALC).
Write a comprehensive, SEO-optimized blog post about: "{keyword}"

المتطلبات:
- اللغة: العربية (Arabic)
- عدد الكلمات الإجمالي: حوالي {words} كلمة
- الهيكل: {sections} أقسام رئيسية مع عناوين H2
- الجمهور المستهدف: الأفراد العسكريون الذين يستعدون لاختبارات الكفاءة في اللغة الإنجليزية ALCPT/ALC
- النبرة: احترافية، مفيدة، مشجعة
- اذكر منصة {site} (على الرابط {site_url}) كمورد مجاني 1-2 مرات بشكل طبيعي

صيغة المخرجات (أرجع JSON صالح فقط):
{{
  "title": "عنوان محسن لمحركات البحث (50-60 حرف)",
  "excerpt": "وصف الميتا (150-160 حرف)",
  "content": "المقال كامل بتنسيق HTML مع استخدام وسوم <h2>, <p>, <ul>, <li>, <strong> فقط. لا تستخدم وسوم <html>, <head>, <body>."
}}

الكلمة المفتاحية للتركيز عليها بشكل طبيعي في العنوان والفقرة الأولى والعناوين: {keyword}
"""
    else:
        prompt = f"""You are an expert SEO content writer specializing in English language learning for military personnel (ALCPT/ALC).

Write a comprehensive, SEO-optimized blog post about: "{keyword}"

REQUIREMENTS:
- Language: English
- Total words: approximately {words} words
- Structure: {sections} main sections with H2 headings
- Target audience: Military personnel preparing for ALCPT/ALC English proficiency tests
- Tone: Professional, helpful, encouraging
- Naturally mention {site} platform (at {site_url}) as a free resource 1-2 times

OUTPUT FORMAT (return ONLY valid JSON):
{{
  "title": "SEO-optimized title (50-60 chars)",
  "excerpt": "Meta description (150-160 chars)",
  "content": "Full HTML article with <h2>, <p>, <ul>, <li>, <strong> tags only. No <html>, <head>, <body> tags."
}}

Focus keyword to use naturally in title, first paragraph, and headings: {keyword}
"""

    url = "https://api.groq.com/openai/v1/chat/completions"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }
    payload = {
        "model": model,
        "messages": [
            {"role": "system", "content": "You are a helpful assistant that strictly outputs valid JSON only."},
            {"role": "user", "content": prompt}
        ],
        "temperature": 0.7,
        "max_completion_tokens": 3000,
        "response_format": {"type": "json_object"}
    }

    log(f"Calling Groq API for keyword: '{keyword}' in language: {lang}")
    resp = requests.post(url, headers=headers, json=payload, timeout=60)
    resp.raise_for_status()

    raw = resp.json()
    text = raw["choices"][0]["message"]["content"].strip()
    
    article = json.loads(text)
    
    # === إضافة روابط التطبيقات الثابتة في آخر المقال ===
    if lang == "ar":
        cta_html = f"""
        <hr>
        <h2>📱 احصل على تطبيق {site} الآن!</h2>
        <p>عزز رحلتك في التحضير لاختبار ALCPT وإتقان اللغة الإنجليزية من خلال تطبيقنا الرسمي:</p>
        <ul>
          <li><strong>لمستخدمي أندرويد:</strong> <a href="https://play.google.com/store/apps/details?id=com.bytronex.lexicore" target="_blank" rel="noopener">حمّل LexiCore من متجر Google Play</a></li>
          <li><strong>لمستخدمي آيفون (iOS):</strong> <a href="https://apps.apple.com/us/app/alcpt-cat-practice-lexicore/id6761208858" target="_blank" rel="noopener">حمّل تطبيق LexiCore للـ iOS من متجر App Store</a></li>
        </ul>
        """
    else:
        cta_html = f"""
        <hr>
        <h2>📱 Get the {site} App Now!</h2>
        <p>Enhance your ALCPT preparation and English proficiency journey with our official app:</p>
        <ul>
          <li><strong>Android Users:</strong> <a href="https://play.google.com/store/apps/details?id=com.bytronex.lexicore" target="_blank" rel="noopener">Download LexiCore from Google Play</a></li>
          <li><strong>iPhone (iOS) Users:</strong> <a href="https://apps.apple.com/us/app/alcpt-cat-practice-lexicore/id6761208858" target="_blank" rel="noopener">Download LexiCore for iOS from the App Store</a></li>
        </ul>
        """
    article["content"] += cta_html
    # ====================================================

    log(f"Article generated ({lang}): '{article['title']}'")
    return article


# ═══════════════════════════════════════════════════════════
# 4. جلب صورة من Unsplash (مجاني)
# ═══════════════════════════════════════════════════════════

def fetch_unsplash_image(access_key: str, keyword: str) -> Optional[bytes]:
    """
    يجلب صورة مجانية من Unsplash بناءً على الـ keyword.
    يُرجع: bytes (بيانات الصورة) أو None لو فشل.
    """
    search_query = keyword.replace("/", " ").replace("quiz", "").strip()
    # استخدام كلمات بحث أعم لنتائج أفضل
    if "ALCPT" in search_query or "ALC" in search_query:
        search_query = "English language learning military education"

    url = "https://api.unsplash.com/photos/random"
    params = {
        "query": search_query,
        "orientation": "landscape",
        "count": 1
    }
    headers = {"Authorization": f"Client-ID {access_key}"}

    log(f"Fetching Unsplash image for: '{search_query}'")
    try:
        resp = requests.get(url, params=params, headers=headers, timeout=30)
        resp.raise_for_status()
        photos = resp.json()
        photo = photos[0] if isinstance(photos, list) else photos
        img_url = photo["urls"]["regular"]

        img_resp = requests.get(img_url, timeout=30)
        img_resp.raise_for_status()
        log("Unsplash image downloaded successfully.")
        return img_resp.content
    except Exception as e:
        log(f"Unsplash fetch failed: {e}", "WARNING")
        return None


# ═══════════════════════════════════════════════════════════
# 5. رفع الصورة لـ WordPress Media
# ═══════════════════════════════════════════════════════════

def upload_wp_media(cfg: dict, image_bytes: bytes, filename: str) -> Optional[int]:
    """
    يرفع الصورة لـ WordPress Media Library.
    يُرجع: media_id أو None لو فشل.
    """
    wp_url  = cfg["wordpress"]["url"].rstrip("/")
    user    = cfg["wordpress"]["username"]
    app_pwd = cfg["wordpress"]["app_password"]

    credentials = base64.b64encode(f"{user}:{app_pwd}".encode()).decode()
    headers = {
        "Authorization": f"Basic {credentials}",
        "Content-Disposition": f'attachment; filename="{filename}"',
        "Content-Type": "image/jpeg"
    }

    endpoint = f"{wp_url}/wp-json/wp/v2/media"
    log(f"Uploading media to WordPress: {filename}")
    try:
        resp = requests.post(endpoint, headers=headers, data=image_bytes, timeout=60)
        resp.raise_for_status()
        media_id = resp.json()["id"]
        log(f"Media uploaded with ID: {media_id}")
        return media_id
    except Exception as e:
        log(f"Media upload failed: {e}", "WARNING")
        return None


# ═══════════════════════════════════════════════════════════
# 6. نشر البوست على WordPress
# ═══════════════════════════════════════════════════════════

def publish_wp_post(cfg: dict, article: dict, media_id: Optional[int], keyword: str) -> dict:
    """
    ينشر البوست على WordPress عبر REST API.
    يُرجع: بيانات البوست المنشور.
    """
    wp_url    = cfg["wordpress"]["url"].rstrip("/")
    user      = cfg["wordpress"]["username"]
    app_pwd   = cfg["wordpress"]["app_password"]
    status    = cfg["wordpress"].get("post_status", "publish")
    category  = cfg["wordpress"].get("default_category", 1)

    credentials = base64.b64encode(f"{user}:{app_pwd}".encode()).decode()
    headers = {
        "Authorization": f"Basic {credentials}",
        "Content-Type": "application/json"
    }

    payload = {
        "title":   article["title"],
        "content": article["content"],
        "excerpt": article.get("excerpt", ""),
        "status":  status,
        "categories": [category],
        "tags": [],
        "meta": {}
    }

    # إضافة الصورة البارزة لو موجودة
    if media_id:
        payload["featured_media"] = media_id

    endpoint = f"{wp_url}/wp-json/wp/v2/posts"
    log(f"Publishing post to WordPress: '{article['title']}'")
    resp = requests.post(endpoint, headers=headers, json=payload, timeout=60)
    resp.raise_for_status()

    post_data = resp.json()
    post_url  = post_data.get("link", "")
    post_id   = post_data.get("id", 0)
    log(f"✅ Post published! ID: {post_id} | URL: {post_url}")
    return post_data


# ═══════════════════════════════════════════════════════════
# 7. تحديث ملف التتبع
# ═══════════════════════════════════════════════════════════

def update_progress(progress: dict, keyword: str, index: int, post_id: int, post_url: str):
    """يحدّث progress.json بعد كل نشر ناجح."""
    progress["last_index"] = index
    progress["last_run"]   = datetime.now().isoformat()
    progress["stats"]["total_published"] = progress["stats"].get("total_published", 0) + 1
    progress["published_posts"].append({
        "index":    index,
        "keyword":  keyword,
        "post_id":  post_id,
        "post_url": post_url,
        "date":     datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    })
    return progress


def send_admin_notification(cfg: dict, message: str):
    """إرسال إشعارات عبر اليوزربوت (باسم @haarods)."""
    # البحث عن إعدادات اليوزربوت في ملف إعدادات السوشيال (لأنها ليست في config.json الخاص بالووردبريس)
    social_config_path = os.path.abspath(os.path.join(SCRIPT_DIR, "..", "social_auto_poster", "social_config.json"))
    if not os.path.exists(social_config_path): return
    
    with open(social_config_path, "r", encoding="utf-8") as f:
        social_cfg = json.load(f)
    
    tg_u = social_cfg.get("telegram_userbot", {})
    if not tg_u.get("enabled"): return

    api_id = tg_u.get("api_id")
    api_hash = tg_u.get("api_hash")
    targets = ["@alcpt_practice", "@haarods"]
    
    if not api_id or not api_hash: return

    import asyncio
    try:
        from telethon import TelegramClient
    except ImportError:
        return

    async def _send():
        # نستخدم نفس مسار الجلسة الموجود في مجلد السوشيال ميديا لتوحيد الدخول
        session_path = os.path.abspath(os.path.join(SCRIPT_DIR, "..", "social_auto_poster", "lexicore_userbot"))
        client = TelegramClient(session_path, api_id, api_hash)
        await client.connect()
        if not await client.is_user_authorized():
            return
        for target in targets:
            try:
                await client.send_message(target, message, parse_mode='html')
            except:
                pass
        await client.disconnect()

    try:
        loop = asyncio.get_event_loop()
        if loop.is_running():
            asyncio.ensure_future(_send())
        else:
            loop.run_until_complete(_send())
    except:
        pass


# ═══════════════════════════════════════════════════════════
# 8. التحقق من الإعدادات
# ═══════════════════════════════════════════════════════════

def validate_config(cfg: dict) -> bool:
    """يتحقق أن جميع المطلوبات موجودة في config.json."""
    errors = []
    if "YOUR_GROQ_API_KEY_HERE" in cfg.get("groq", {}).get("api_key", "") or not cfg.get("groq", {}).get("api_key"):
        errors.append("❌ Groq API Key غير مضبوطة في config.json")
    if "YOUR_WP_USERNAME" in cfg["wordpress"]["username"]:
        errors.append("❌ WordPress Username غير مضبوط في config.json")
    if "YOUR_WP_APPLICATION_PASSWORD" in cfg["wordpress"]["app_password"]:
        errors.append("❌ WordPress Application Password غير مضبوط في config.json")
    if errors:
        for e in errors:
            log(e, "ERROR")
        return False
    return True


# ═══════════════════════════════════════════════════════════
# 9. الدالة الرئيسية
# ═══════════════════════════════════════════════════════════

def main():
    parser = argparse.ArgumentParser(description="WordPress Auto-Post (Free)")
    parser.add_argument("--test",       action="store_true", help="وضع الاختبار: ينشر كـ draft")
    parser.add_argument("--keyword",    type=str,            help="تحديد keyword يدوياً")
    parser.add_argument("--lang",       type=str,            choices=["en", "ar"], help="لغة المقال (en أو ar)")
    parser.add_argument("--dry-run",    action="store_true", help="توليد المقال فقط بدون نشر")
    parser.add_argument("--reset",      action="store_true", help="إعادة تعيين progress.json من البداية")
    args = parser.parse_args()

    log("=" * 55)
    log("WordPress Auto-Post — learn-lexicore.bytronex.com")
    log("=" * 55)

    # ── تحميل الإعدادات ──
    if not os.path.exists(CONFIG_FILE):
        log("config.json غير موجود! نفّذ: cp config.json.example config.json", "ERROR")
        sys.exit(1)

    cfg      = load_json(CONFIG_FILE)
    progress = load_json(PROGRESS_FILE) if os.path.exists(PROGRESS_FILE) else {
        "last_index": -1, "published_posts": [], "last_run": None,
        "stats": {"total_published": 0, "total_failed": 0}
    }
    keywords = load_keywords()

    log(f"Keywords loaded: {len(keywords)} total")
    log(f"Published so far: {progress['stats'].get('total_published', 0)}")

    # ── إعادة التعيين ──
    if args.reset:
        progress = {"last_index": -1, "published_posts": [], "last_run": None,
                    "stats": {"total_published": 0, "total_failed": 0}}
        save_json(PROGRESS_FILE, progress)
        log("✅ Progress reset to beginning.")
        return

    # ── التحقق من الإعدادات ──
    # في dry-run نتحقق من Groq فقط (لا نحتاج WordPress)
    if args.dry_run:
        if "YOUR_GROQ_API_KEY_HERE" in cfg.get("groq", {}).get("api_key", ""):
            log("❌ Groq API Key غير مضبوطة في config.json", "ERROR")
            sys.exit(1)
    elif not validate_config(cfg):
        log("عدّل config.json أولاً قبل التشغيل.", "ERROR")
        sys.exit(1)

    # ── وضع الاختبار: يجبر draft ──
    if args.test:
        cfg["wordpress"]["post_status"] = "draft"
        log("[TEST MODE] Post will be saved as DRAFT.")

    # ── لغة المقال ──
    lang = args.lang if args.lang else cfg["settings"].get("article_language", "en")

    # ── اختيار الـ Keyword ──
    if args.keyword:
        keyword = args.keyword
        index   = progress.get("last_index", -1)  # لا يحرّك الـ index
        log(f"Manual keyword: '{keyword}'")
    else:
        keyword, index = pick_next_keyword(keywords, progress)
        log(f"Auto keyword [{index+1}/{len(keywords)}]: '{keyword}'")

    # ── توليد المقال ──
    try:
        article = generate_article(cfg, keyword, lang)
    except Exception as e:
        log(f"Failed to generate article: {e}", "ERROR")
        progress["stats"]["total_failed"] = progress["stats"].get("total_failed", 0) + 1
        save_json(PROGRESS_FILE, progress)
        sys.exit(1)

    if args.dry_run:
        log("[DRY RUN] Article generated. No post published.")
        print("\n--- TITLE ---")
        print(article["title"])
        print("\n--- EXCERPT ---")
        print(article.get("excerpt", ""))
        print("\n--- CONTENT (first 500 chars) ---")
        print(article["content"][:500] + "...")
        return

    # ── جلب الصورة (مجانية) ──
    media_id = None
    unsplash_key = cfg.get("unsplash", {}).get("access_key", "")
    if unsplash_key and "YOUR_UNSPLASH_ACCESS_KEY_HERE" not in unsplash_key:
        img_bytes = fetch_unsplash_image(unsplash_key, keyword)
        if img_bytes:
            safe_name = keyword.replace(" ", "_").replace("/", "_")[:40]
            filename  = f"{safe_name}_{datetime.now().strftime('%Y%m%d')}.jpg"
            media_id  = upload_wp_media(cfg, img_bytes, filename)
    else:
        log("Unsplash key not set — skipping featured image.", "WARNING")

    # ── نشر على WordPress ──
    try:
        post_data = publish_wp_post(cfg, article, media_id, keyword)
        post_id   = post_data.get("id", 0)
        post_url  = post_data.get("link", "")

        # ── تحديث التتبع ──
        progress = update_progress(progress, keyword, index, post_id, post_url)
        save_json(PROGRESS_FILE, progress)

        remaining = len(keywords) - (index + 1)
        log(f"🎉 Done! Keywords remaining: {remaining}")
        log(f"   Post URL: {post_url}")

        # الإشعار
        lang_str = "الإنجليزية" if lang == "en" else "العربية"
        notif_msg = f"📝 <b>تم نشر مقال جديد على ووردبريس ({lang_str})!</b>\n\n" \
                    f"📌 <b>العنوان:</b> {article['title']}\n" \
                    f"🔑 <b>الكلمة:</b> {keyword}\n" \
                    f"🔗 <b>الرابط:</b> <a href='{post_url}'>{post_url}</a>"
        send_admin_notification(cfg, notif_msg)

    except Exception as e:
        log(f"Failed to publish post: {e}", "ERROR")
        progress["stats"]["total_failed"] = progress["stats"].get("total_failed", 0) + 1
        save_json(PROGRESS_FILE, progress)
        sys.exit(1)


if __name__ == "__main__":
    main()
