#!/usr/bin/env python3
"""
Cleanup favorites: unfavorite properties ranked below top N on Properstar and Leggett.

Uses the scorer's ranked output (cyber_prairie_shortlist.json) as the source of truth.

Usage:
    python3 cleanup_favorites.py --dry-run          # Preview what would be removed
    python3 cleanup_favorites.py --top 20            # Remove everything below top 20
    python3 cleanup_favorites.py --top 20 --execute  # Actually unfavorite on platforms
"""
import argparse
import asyncio
import json
import sys
from datetime import datetime, timezone
from pathlib import Path

from store import load, save, export_enriched, detect_source, STATUS_REMOVED

SCRIPT_DIR = Path(__file__).parent
SHORTLIST_PATH = SCRIPT_DIR / 'cyber_prairie_shortlist.json'
REMOVED_PATH = SCRIPT_DIR / 'removed_properties.json'
AUTH_JSON = SCRIPT_DIR / 'auth.json'


def load_ranked():
    """Load ranked properties from scorer output."""
    if not SHORTLIST_PATH.exists():
        print(f"No {SHORTLIST_PATH.name} found. Run cyber_prairie_score.py first.")
        sys.exit(1)
    with open(SHORTLIST_PATH, encoding='utf-8') as f:
        data = json.load(f)
    shortlist = data.get('shortlist', [])
    gated = data.get('gated', [])
    return shortlist + gated


def identify_removals(ranked, top_n):
    """Split ranked list into keepers and removals for Properstar + Leggett."""
    keepers = ranked[:top_n]
    candidates = ranked[top_n:]

    to_remove = []
    for rank, prop in enumerate(candidates, top_n + 1):
        url = prop.get('url', '')
        source = detect_source(url)
        if source in ('properstar', 'leggett'):
            to_remove.append({
                'url': url,
                'source': source,
                'rank': rank,
                'cp_score': prop.get('cp_score', 0),
                'location': prop.get('location', '?'),
                'title': prop.get('title', '')[:50],
            })

    return keepers, to_remove


def add_to_blacklist(urls):
    """Add URLs to the permanent removed properties blacklist."""
    if REMOVED_PATH.exists():
        with open(REMOVED_PATH, 'r', encoding='utf-8') as f:
            blacklist = json.load(f)
    else:
        blacklist = []
    added = 0
    for url in urls:
        if url not in blacklist:
            blacklist.append(url)
            added += 1
    with open(REMOVED_PATH, 'w', encoding='utf-8') as f:
        json.dump(blacklist, f, indent=2, ensure_ascii=False)
    return added


def mark_removed_in_store(urls):
    """Mark properties as Removed in the store."""
    store = load()
    marked = 0
    for url in urls:
        if url in store:
            store[url]['status'] = STATUS_REMOVED
            store[url]['removed_at'] = datetime.now(timezone.utc).isoformat()
            store[url]['removed_reason'] = 'Below top N cutoff'
            marked += 1
    save(store)
    export_enriched(store)
    return marked


async def unfavorite_properstar(page, url):
    """Unfavorite a single property on Properstar."""
    await page.goto(url, timeout=30000)
    await page.wait_for_load_state('domcontentloaded')
    await page.wait_for_timeout(1500)

    selectors = [
        'button[aria-label*="favorite" i]',
        'button[aria-label*="Favoriet" i]',
        'button[aria-label*="Remove" i]',
        'button[title*="favorite" i]',
        'button.favorite-button',
        '.favorite-btn',
        '[data-testid*="favorite"]',
    ]

    for selector in selectors:
        try:
            btn = await page.wait_for_selector(selector, timeout=2000)
            if btn:
                await btn.click()
                await page.wait_for_timeout(800)
                return True
        except Exception:
            continue

    # Fallback: search for heart icon in any button
    buttons = await page.query_selector_all('button')
    for button in buttons:
        html = await button.inner_html()
        if 'heart' in html.lower() or 'favorite' in html.lower() or 'favoriet' in html.lower():
            await button.click()
            await page.wait_for_timeout(800)
            return True

    return False


async def unfavorite_leggett(page, url):
    """Unfavorite a single property on Leggett (frenchestateagents.com)."""
    await page.goto(url, timeout=30000)
    await page.wait_for_load_state('domcontentloaded')
    await page.wait_for_timeout(1500)

    selectors = [
        'button[aria-label*="shortlist" i]',
        'button[aria-label*="favorite" i]',
        'a.shortlist-button',
        '.shortlist-btn',
        '.add-to-shortlist',
        '[data-action*="shortlist"]',
        'a[title*="shortlist" i]',
        'button[title*="shortlist" i]',
    ]

    for selector in selectors:
        try:
            btn = await page.wait_for_selector(selector, timeout=2000)
            if btn:
                await btn.click()
                await page.wait_for_timeout(800)
                return True
        except Exception:
            continue

    # Fallback: look for heart/star/shortlist text
    for tag in ['button', 'a']:
        elements = await page.query_selector_all(tag)
        for el in elements:
            text = (await el.inner_text()).lower()
            html = (await el.inner_html()).lower()
            if any(kw in text or kw in html for kw in ['shortlist', 'heart', 'favorite', 'remove from']):
                await el.click()
                await page.wait_for_timeout(800)
                return True

    return False


async def execute_unfavoriting(to_remove):
    """Open browser and unfavorite properties on both platforms."""
    from playwright.async_api import async_playwright

    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)

        # Properstar context (with auth)
        if AUTH_JSON.exists():
            ps_context = await browser.new_context(storage_state=str(AUTH_JSON))
        else:
            print("  No auth.json for Properstar. Will try without login.")
            ps_context = await browser.new_context()
        ps_page = await ps_context.new_page()

        # Leggett context (no auth needed for shortlist, uses cookies)
        lg_context = await browser.new_context()
        lg_page = await lg_context.new_page()

        success = 0
        failed = []

        for i, item in enumerate(to_remove, 1):
            url = item['url']
            source = item['source']
            print(f"  [{i}/{len(to_remove)}] {source:11} | {item['location'][:30]}")

            try:
                if source == 'properstar':
                    ok = await unfavorite_properstar(ps_page, url)
                else:
                    ok = await unfavorite_leggett(lg_page, url)

                if ok:
                    print(f"    Unfavorited")
                    success += 1
                else:
                    print(f"    Button not found, skipping")
                    failed.append(item)
            except Exception as e:
                print(f"    Error: {e}")
                failed.append(item)

        await browser.close()

    return success, failed


def print_summary(keepers, to_remove, top_n):
    """Print overview of what stays and what goes."""
    from collections import Counter
    remove_sources = Counter(p['source'] for p in to_remove)
    keep_sources = Counter()
    for p in keepers:
        url = p.get('url', '')
        s = detect_source(url)
        if s in ('properstar', 'leggett'):
            keep_sources[s] += 1

    print(f"\n{'=' * 60}")
    print(f"  CLEANUP FAVORITES — Top {top_n} cutoff")
    print(f"{'=' * 60}")
    print(f"\n  Keeping (top {top_n}):")
    print(f"    Properstar: {keep_sources.get('properstar', 0)}")
    print(f"    Leggett:    {keep_sources.get('leggett', 0)}")
    print(f"\n  Removing (rank {top_n + 1}+):")
    print(f"    Properstar: {remove_sources.get('properstar', 0)}")
    print(f"    Leggett:    {remove_sources.get('leggett', 0)}")
    print(f"    Total:      {len(to_remove)}")
    print()


def main():
    parser = argparse.ArgumentParser(description='Cleanup favorites below top N ranking')
    parser.add_argument('--top', type=int, default=20, help='Keep top N properties (default: 20)')
    parser.add_argument('--dry-run', action='store_true', help='Preview removals without making changes')
    parser.add_argument('--execute', action='store_true', help='Actually unfavorite on platforms via browser')
    parser.add_argument('--store-only', action='store_true', help='Only mark as removed in store, skip browser')
    args = parser.parse_args()

    ranked = load_ranked()
    keepers, to_remove = identify_removals(ranked, args.top)
    print_summary(keepers, to_remove, args.top)

    if not to_remove:
        print("Nothing to remove.")
        return

    if args.dry_run:
        print("  DRY RUN — properties that would be removed:\n")
        for item in to_remove:
            print(f"    #{item['rank']:3} CP={item['cp_score']:.2f} | {item['source']:11} | {item['location']}")
        print(f"\n  Run with --execute to unfavorite on platforms.")
        print(f"  Run with --store-only to mark as removed in store without browser.")
        return

    if not args.execute and not args.store_only:
        print("  Add --dry-run to preview, --execute to unfavorite, or --store-only to update store.")
        return

    # Step 1: Mark removed in store + blacklist
    urls = [item['url'] for item in to_remove]
    print(f"  Marking {len(urls)} properties as removed in store...")
    marked = mark_removed_in_store(urls)
    added = add_to_blacklist(urls)
    print(f"    Store: {marked} marked | Blacklist: {added} added")

    # Step 2: Browser unfavoriting (if --execute)
    if args.execute:
        print(f"\n  Opening browser to unfavorite {len(to_remove)} properties...\n")
        success, failed = asyncio.run(execute_unfavoriting(to_remove))
        print(f"\n  {'=' * 40}")
        print(f"  Browser results: {success} unfavorited, {len(failed)} failed")
        if failed:
            print(f"  Failed URLs:")
            for item in failed:
                print(f"    {item['source']:11} | {item['url']}")
        print(f"  {'=' * 40}")
    else:
        print(f"\n  Store updated. Skipped browser unfavoriting (use --execute for that).")


if __name__ == '__main__':
    main()
