#!/usr/bin/env python3
"""
Pinterest Automation - Post to Pinterest via Publer API
Posts all JPGs (except whats-included.jpg) from one listing per run
"""

import json
import sys
import requests
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional
import logging
import time
import base64

# Add parent to path for config
sys.path.insert(0, str(Path(__file__).parent))
from config import *

# Setup logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(LOG_DIR / "pinterest-post.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)


def get_headers() -> dict:
    """Get Publer API headers"""
    return {
        "Authorization": f"Bearer-API {PUBLER_API_KEY}",
        "Publer-Workspace-Id": PUBLER_WORKSPACE_ID,
        "Content-Type": "application/json"
    }


def load_listings() -> dict:
    """Load listings JSON"""
    if not LISTINGS_JSON.exists():
        logger.error(f"Listings file not found: {LISTINGS_JSON}")
        sys.exit(1)
    
    with open(LISTINGS_JSON, 'r') as f:
        return json.load(f)


def save_listings(data: dict):
    """Save listings JSON"""
    with open(LISTINGS_JSON, 'w') as f:
        json.dump(data, f, indent=2)


def find_archive_folder(listing: dict) -> Optional[Path]:
    """Find archive folder matching a listing by title keywords."""
    title = listing.get("title", "").lower()
    
    exclude_folders = ["listed", "rejected", "source-pngs", "cleanup-20260210"]
    archive_folders = [
        f for f in ARCHIVE_DIR.iterdir() 
        if f.is_dir() and f.name not in exclude_folders
    ]
    
    title_words = []
    for word in title.lower().replace(",", "").replace("-", " ").split():
        if len(word) > 3 and word not in ["with", "for", "the", "and", "svg", "cut", "file", "cricut", "silhouette"]:
            title_words.append(word)
    title_words = title_words[:4]
    
    best_match = None
    best_score = 0
    
    for folder in archive_folders:
        folder_name = folder.name.lower().replace("_", " ").replace("-", " ")
        score = sum(1 for w in title_words if w in folder_name)
        if score > best_score:
            best_score = score
            best_match = folder
    
    if best_score >= 2:
        return best_match
    return None


def get_images_to_post(folder: Path) -> list[Path]:
    """Get all JPGs from folder, excluding whats-included"""
    images = []
    for img in folder.glob("*.jpg"):
        if img.name.lower() not in [e.lower() for e in EXCLUDED_FILES]:
            images.append(img)
    return sorted(images)


def get_next_unposted_listing(data: dict) -> Optional[dict]:
    """Find next listing that has unposted images."""
    listings = data.get("listings", [])
    
    # Priority listings first
    for listing in listings:
        if listing.get("priority", False) and not listing.get("delisted"):
            posted = set(listing.get("posted_images", []))
            folder = find_archive_folder(listing)
            if folder:
                images = get_images_to_post(folder)
                unposted = [img for img in images if img.name not in posted]
                if unposted:
                    return listing
    
    # Then regular listings
    for listing in listings:
        if listing.get("priority", False) or listing.get("delisted"):
            continue
        posted = set(listing.get("posted_images", []))
        folder = find_archive_folder(listing)
        if folder:
            images = get_images_to_post(folder)
            unposted = [img for img in images if img.name not in posted]
            if unposted:
                return listing
    
    return None


def upload_media(image_path: Path) -> Optional[dict]:
    """
    Upload image to Publer Media Library.
    Returns dict with id, path, thumbnail on success.
    """
    headers = {
        "Authorization": f"Bearer-API {PUBLER_API_KEY}",
        "Publer-Workspace-Id": PUBLER_WORKSPACE_ID
    }
    
    try:
        with open(image_path, 'rb') as f:
            files = {'file': (image_path.name, f, 'image/jpeg')}
            resp = requests.post(
                f"{PUBLER_API_BASE}/media",
                headers=headers,
                files=files,
                data={'direct_upload': 'true', 'in_library': 'false'}
            )
            resp.raise_for_status()
            result = resp.json()
            media_id = result.get("id") or result.get("_id")
            media_path = result.get("path", "")
            media_thumb = result.get("thumbnail", "")
            logger.info(f"Uploaded media: {image_path.name} -> {media_id}")
            return {
                "id": media_id,
                "path": media_path,
                "thumbnail": media_thumb
            }
    except Exception as e:
        logger.error(f"Failed to upload media {image_path.name}: {e}")
        if hasattr(e, 'response') and e.response is not None:
            logger.error(f"Response: {e.response.text[:500]}")
        return None


def poll_job_status(job_id: str, max_attempts: int = 30) -> Optional[dict]:
    """Poll job status until completed or failed."""
    headers = get_headers()
    
    for attempt in range(max_attempts):
        try:
            resp = requests.get(
                f"{PUBLER_API_BASE}/job_status/{job_id}",
                headers=headers
            )
            resp.raise_for_status()
            result = resp.json()
            
            # Handle case where result is a list (Publer sometimes returns array)
            if isinstance(result, list):
                result = result[0] if result else {}
            
            status = result.get("status") if isinstance(result, dict) else None
            if status in ["completed", "complete"]:
                # Check for failures
                payload = result.get("payload", {}) if isinstance(result, dict) else {}
                failures = payload.get("failures", {}) if isinstance(payload, dict) else {}
                if failures:
                    logger.warning(f"Job completed with failures: {failures}")
                return result
            elif status == "failed":
                logger.error(f"Job failed: {result}")
                return None
            
            # Still working, wait and retry
            time.sleep(1)
        except Exception as e:
            logger.error(f"Error polling job status: {e}")
            time.sleep(1)
    
    logger.error(f"Job polling timed out after {max_attempts} attempts")
    return None


def create_pinterest_pin(
    media_info: dict,
    title: str,
    description: str,
    link: str,
    board_id: str
) -> bool:
    """
    Create a Pinterest pin via Publer API.
    Uses the correct Publer Pinterest format.
    """
    headers = get_headers()
    
    # Correct Publer Pinterest format per documentation
    payload = {
        "bulk": {
            "state": "scheduled",
            "posts": [
                {
                    "networks": {
                        "pinterest": {
                            "type": "photo",
                            "text": description[:500],
                            "title": title[:100],
                            "url": link,
                            "media": [
                                {
                                    "id": media_info["id"],
                                    "type": "photo",
                                    "path": media_info.get("path", ""),
                                    "thumbnail": media_info.get("thumbnail", "")
                                }
                            ]
                        }
                    },
                    "accounts": [
                        {
                            "id": PINTEREST_ACCOUNT_ID,
                            "album_id": board_id
                            # NO scheduled_at = publish immediately
                        }
                    ]
                }
            ]
        }
    }
    
    try:
        # Use schedule/publish endpoint for immediate publishing
        resp = requests.post(
            f"{PUBLER_API_BASE}/posts/schedule/publish",
            headers=headers,
            json=payload
        )
        resp.raise_for_status()
        result = resp.json()
        
        # Check if we got a job_id (async processing)
        job_id = result.get("job_id")
        if job_id:
            logger.info(f"Post submitted, job_id: {job_id}")
            # Poll for completion
            final = poll_job_status(job_id)
            if final:
                logger.info(f"Pin published successfully")
                return True
            else:
                return False
        else:
            logger.info(f"Pin created: {result}")
            return True
            
    except Exception as e:
        logger.error(f"Failed to create pin: {e}")
        if hasattr(e, 'response') and e.response is not None:
            logger.error(f"Response: {e.response.text[:500]}")
        return False


def generate_description(listing: dict) -> str:
    """Generate Pinterest-optimized description"""
    title = listing.get("title", "")
    url = listing.get("url", "")
    category = listing.get("category", "")
    niche = CATEGORY_TO_NICHE.get(category, "christian")
    
    niche_tags = {
        "military": "#USMC #MarineCorps #VeteranMade #MilitaryLife #SemperFi",
        "patriotic": "#USA #PatrioticDecor #AmericanMade #4thOfJuly #RedWhiteBlue",
        "christian": "#ChristianArt #FaithBased #ChurchDecor #ReformedTheology #Easter",
        "outdoor": "#HuntingLife #WildlifeArt #CabinDecor #OutdoorLife #NatureArt"
    }
    
    description = f"""✨ {title} ✨

Perfect for Cricut, Silhouette, laser cutters & vinyl cutting machines!

🎨 Instant digital download includes:
• SVG file (vector, infinitely scalable)
• PNG file (high resolution, transparent background)

💡 Create stunning:
• T-shirts & apparel
• Tumblers & mugs  
• Wall art & signs
• Car decals & stickers

{niche_tags.get(niche, niche_tags['christian'])} #SVGCutFile #DigitalDownload #CricutMade
"""
    return description.strip()


def post_listing_images(listing: dict, data: dict) -> int:
    """Post all unposted images from a listing. Returns count."""
    folder = find_archive_folder(listing)
    if not folder:
        logger.warning(f"No archive folder found for: {listing.get('title', 'Unknown')[:50]}")
        return 0
    
    posted = set(listing.get("posted_images", []))
    images = get_images_to_post(folder)
    unposted = [img for img in images if img.name not in posted]
    
    if not unposted:
        logger.info(f"All images already posted for: {listing.get('title', '')[:50]}")
        return 0
    
    description = listing.get("pinterest_description") or generate_description(listing)
    category = listing.get("category", "")
    board_id = PINTEREST_BOARD_IDS.get(category, PINTEREST_BOARD_IDS["Easter SVGs"])
    
    posted_count = 0
    for img in unposted:
        logger.info(f"Posting: {img.name}")
        
        # Upload image first
        media_info = upload_media(img)
        if not media_info:
            logger.error(f"Failed to upload: {img.name}")
            continue
        
        # Create pin with correct format
        success = create_pinterest_pin(
            media_info=media_info,
            title=listing.get("title", ""),
            description=description,
            link=listing.get("url", ""),
            board_id=board_id
        )
        
        if success:
            if "posted_images" not in listing:
                listing["posted_images"] = []
            listing["posted_images"].append(img.name)
            listing["last_posted"] = datetime.now().isoformat()
            posted_count += 1
            save_listings(data)
            time.sleep(2)
    
    return posted_count


def main():
    """Main entry point - post one listing's images"""
    logger.info("=" * 50)
    logger.info("Pinterest Automation - Starting")
    
    data = load_listings()
    listing = get_next_unposted_listing(data)
    
    if not listing:
        logger.info("No listings with unposted images found")
        print("ALL_POSTED")
        return
    
    logger.info(f"Processing: {listing.get('title', '')[:60]}")
    posted = post_listing_images(listing, data)
    
    logger.info(f"Posted {posted} images for listing")
    logger.info("=" * 50)
    
    if posted > 0:
        print(f"SUCCESS: Posted {posted} images for '{listing.get('title', '')[:40]}...'")
    else:
        print("FAILED: No images posted")


if __name__ == "__main__":
    main()
