#!/usr/bin/env python3
"""
Find construction timelapse TikTok profiles and collect viral videos.
Filters: 1M+ views, 50-90s duration.
Outputs HTML page with all links for bulk download.
"""

import httpx
import json
import time
from datetime import datetime

API_KEY = "vUELI81uMMWm8tQkgj3N6BXAsag1"
BASE_URL = "https://api.scrapecreators.com"
HEADERS = {"x-api-key": API_KEY, "Content-Type": "application/json"}

MIN_VIEWS = 1_000_000
MIN_DURATION_MS = 50_000   # 50s in ms
MAX_DURATION_MS = 90_000   # 1m30s in ms
TARGET_VIDEOS = 200

SEARCH_QUERIES = [
    "construction timelapse",
    "house building timelapse",
    "building construction timelapse",
    "home construction timelapse",
    "house build timelapse",
    "ai house build timelapse",
    "mansion build timelapse",
    "dream house build timelapse",
    "house construction process timelapse",
    "building a house start to finish",
    "construction time lapse satisfying",
    "home building process timelapse",
    "foundation to finish house",
    "house build start to finish",
    "modern house construction timelapse",
    "luxury house build timelapse",
    "pool construction timelapse",
    "concrete house timelapse",
    "house framing timelapse",
    "new build house timelapse",
    "house transformation timelapse",
    "home renovation timelapse complete",
    "construction progress timelapse",
    "amazing house build timelapse",
    "incredible construction timelapse",
    "tiny house build timelapse",
    "container house build",
    "barndominium build timelapse",
    "basement finishing timelapse",
    "custom home build timelapse",
    "steel frame house build",
    "house build 2024 timelapse",
    "house build 2025 timelapse",
    "construction satisfying video",
    "house building viral",
    "construction viral tiktok",
    "house build process viral",
    "diy house build timelapse",
    "cabin build timelapse",
    "garage build timelapse",
]

credits_used = 0


def api_request(endpoint, params=None):
    """Make API request."""
    global credits_used
    for attempt in range(3):
        try:
            with httpx.Client(timeout=60) as client:
                resp = client.get(f"{BASE_URL}{endpoint}", params=params, headers=HEADERS)
                if resp.status_code == 200:
                    credits_used += 1
                    return resp.json()
                elif resp.status_code == 429:
                    print(f"    Rate limited, waiting 5s...")
                    time.sleep(5)
                    continue
                else:
                    print(f"    API {resp.status_code}")
                    return None
        except Exception as e:
            print(f"    Error: {e}")
            if attempt < 2:
                time.sleep(2)
    return None


def extract_video_from_search(item):
    """Extract video info from search/top result."""
    if not isinstance(item, dict):
        return None

    video_id = item.get("id", "")
    stats = item.get("statistics", {})
    views = stats.get("play_count", 0)
    likes = stats.get("digg_count", 0)
    collects = stats.get("collect_count", 0)
    shares = stats.get("share_count", 0)

    video_obj = item.get("video", {})
    duration_ms = video_obj.get("duration", 0) if isinstance(video_obj, dict) else 0

    author = item.get("author", {})
    username = author.get("unique_id", "") if isinstance(author, dict) else ""
    nickname = author.get("nickname", "") if isinstance(author, dict) else ""

    desc = item.get("desc", "")
    url = item.get("url", "")
    if not url and video_id and username:
        url = f"https://www.tiktok.com/@{username}/video/{video_id}"

    return {
        "id": str(video_id),
        "url": url,
        "views": int(views),
        "likes": int(likes),
        "collects": int(collects),
        "shares": int(shares),
        "duration_ms": int(duration_ms),
        "duration_s": round(int(duration_ms) / 1000),
        "username": username,
        "nickname": nickname,
        "description": str(desc)[:200],
    }


def extract_video_from_profile(item, fallback_username=""):
    """Extract video info from profile/videos result (aweme_list)."""
    if not isinstance(item, dict):
        return None

    video_id = item.get("aweme_id", item.get("id", ""))
    stats = item.get("statistics", {})
    views = stats.get("play_count", 0)
    likes = stats.get("digg_count", 0)
    collects = stats.get("collect_count", 0)
    shares = stats.get("share_count", 0)

    video_obj = item.get("video", {})
    duration_ms = video_obj.get("duration", 0) if isinstance(video_obj, dict) else 0

    author = item.get("author", {})
    username = author.get("unique_id", fallback_username) if isinstance(author, dict) else fallback_username

    desc = item.get("desc", "")
    share_url = item.get("share_url", "")
    url = share_url if share_url else f"https://www.tiktok.com/@{username}/video/{video_id}"

    return {
        "id": str(video_id),
        "url": url,
        "views": int(views),
        "likes": int(likes),
        "collects": int(collects),
        "shares": int(shares),
        "duration_ms": int(duration_ms),
        "duration_s": round(int(duration_ms) / 1000),
        "username": username,
        "nickname": "",
        "description": str(desc)[:200],
    }


def is_construction_content(text):
    """Check if text relates to construction/building."""
    text = text.lower()
    keywords = [
        "construct", "build", "house", "home", "timelapse", "time lapse",
        "time-lapse", "foundation", "concrete", "framing", "mansion",
        "pool", "renovation", "remodel", "roof", "brick", "drywall",
        "plumbing", "flooring", "basement", "dream home", "new build",
        "custom home", "modern house", "architecture", "contractor",
        "cabin", "garage", "shed", "barn", "tiny house", "container",
        "construção", "casa", "obra", "reforma", "steel frame",
        "excavat", "lumber", "siding", "insulation", "pour",
    ]
    return any(kw in text for kw in keywords)


def video_qualifies(v):
    """Check if video meets criteria."""
    return (v["views"] >= MIN_VIEWS and
            MIN_DURATION_MS <= v["duration_ms"] <= MAX_DURATION_MS)


def main():
    print("=" * 70)
    print("CONSTRUCTION TIMELAPSE VIRAL VIDEO FINDER")
    print(f"Target: {TARGET_VIDEOS}+ videos | Views: {MIN_VIEWS/1e6:.0f}M+ | Duration: {MIN_DURATION_MS//1000}-{MAX_DURATION_MS//1000}s")
    print("=" * 70)

    all_creators = {}  # username -> info
    all_videos = {}    # video_id -> info

    # ── Phase 1: Search top videos to find creators + videos ──
    print(f"\n▶ PHASE 1: Searching {len(SEARCH_QUERIES)} queries for creators & videos...")

    for i, query in enumerate(SEARCH_QUERIES):
        print(f"\n  [{i+1}/{len(SEARCH_QUERIES)}] '{query}'")
        data = api_request("/v1/tiktok/search/top", {"query": query, "count": 30})
        time.sleep(1.2)

        if not data or not isinstance(data, dict):
            continue

        items = data.get("items", [])
        if not items:
            print(f"    No results")
            continue

        found_videos = 0
        for item in items:
            v = extract_video_from_search(item)
            if not v or not v["id"]:
                continue

            # Track creator
            if v["username"] and v["username"] not in all_creators:
                if is_construction_content(v["description"]) or is_construction_content(query):
                    all_creators[v["username"]] = {"source": "search", "query": query, "nickname": v["nickname"]}

            # Save qualifying video
            if video_qualifies(v) and v["id"] not in all_videos:
                if is_construction_content(v["description"]):
                    all_videos[v["id"]] = v
                    found_videos += 1

        print(f"    → {found_videos} qualifying videos, {len(all_creators)} total creators")

    print(f"\n  Phase 1 results: {len(all_videos)} videos from {len(all_creators)} creators")

    # ── Phase 2: Get ALL videos from discovered creators ──
    print(f"\n▶ PHASE 2: Scraping videos from {len(all_creators)} creators...")

    for i, (username, info) in enumerate(list(all_creators.items())):
        print(f"\n  [{i+1}/{len(all_creators)}] @{username} ({info.get('nickname', '')})...")

        cursor = "0"
        page = 0
        creator_vids = 0
        creator_total = 0

        while page < 10:  # up to 10 pages (500 videos)
            params = {"handle": username, "count": 50}
            if cursor and cursor != "0":
                params["cursor"] = cursor

            data = api_request("/v1/tiktok/profile/videos", params)
            time.sleep(1.2)

            if not data or not isinstance(data, dict):
                break

            aweme_list = data.get("aweme_list", [])
            has_more = data.get("has_more", 0)
            next_cursor = str(data.get("max_cursor", "0"))

            if not aweme_list:
                if page == 0:
                    print(f"    No videos found")
                break

            creator_total += len(aweme_list)

            for item in aweme_list:
                v = extract_video_from_profile(item, username)
                if not v or not v["id"]:
                    continue

                if video_qualifies(v) and v["id"] not in all_videos:
                    all_videos[v["id"]] = v
                    creator_vids += 1
                    print(f"    ✓ {v['views']/1e6:.1f}M views | {v['duration_s']}s | {v['description'][:60]}")

            if not has_more or next_cursor == cursor:
                break
            cursor = next_cursor
            page += 1

        if creator_vids > 0:
            print(f"    → {creator_vids} qualifying videos (from {creator_total} total)")
        elif creator_total > 0:
            print(f"    → 0 qualifying (checked {creator_total} videos)")

    print(f"\n  Phase 2 results: {len(all_videos)} total qualifying videos")

    # ── Phase 3: More searches if needed ──
    if len(all_videos) < TARGET_VIDEOS:
        print(f"\n▶ PHASE 3: Need more ({len(all_videos)}/{TARGET_VIDEOS}), doing keyword searches...")

        extra_queries = [
            "house build viral million views",
            "construction viral 2024",
            "construction viral 2025",
            "satisfying construction video",
            "house build completed",
            "dream house construction complete",
            "house build couple timelapse",
            "first time home build",
            "contractor timelapse",
            "house flip timelapse",
            "swimming pool build timelapse",
            "deck build timelapse",
            "addition build timelapse",
            "home extension build",
            "new construction house 2025",
            "house build drone timelapse",
            "building our forever home",
            "house build uk timelapse",
            "house build australia",
            "house build canada timelapse",
        ]

        for query in extra_queries:
            if len(all_videos) >= TARGET_VIDEOS:
                break

            print(f"  Searching: '{query}'")
            data = api_request("/v1/tiktok/search/top", {"query": query, "count": 30})
            time.sleep(1.2)

            if not data or not isinstance(data, dict):
                continue

            for item in data.get("items", []):
                v = extract_video_from_search(item)
                if v and v["id"] and video_qualifies(v) and v["id"] not in all_videos:
                    if is_construction_content(v["description"]):
                        all_videos[v["id"]] = v

                        if v["username"] and v["username"] not in all_creators:
                            all_creators[v["username"]] = {"source": "extra"}
                            # Get this creator's videos too
                            print(f"    New creator @{v['username']}, fetching videos...")
                            pdata = api_request("/v1/tiktok/profile/videos", {"handle": v["username"], "count": 50})
                            time.sleep(1.2)
                            if pdata and isinstance(pdata, dict):
                                for pi in pdata.get("aweme_list", []):
                                    pv = extract_video_from_profile(pi, v["username"])
                                    if pv and pv["id"] and video_qualifies(pv) and pv["id"] not in all_videos:
                                        all_videos[pv["id"]] = pv

    # ── Generate output ──
    sorted_videos = sorted(all_videos.values(), key=lambda x: x["views"], reverse=True)

    if not sorted_videos:
        print("\n❌ No qualifying videos found!")
        return

    all_links = [v["url"] for v in sorted_videos if v["url"]]
    total_views = sum(v["views"] for v in sorted_videos)
    unique_creators = len(set(v["username"] for v in sorted_videos if v["username"]))

    # Generate HTML
    html = f"""<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Construction Timelapse - {len(sorted_videos)} Viral Videos</title>
    <style>
        * {{ margin: 0; padding: 0; box-sizing: border-box; }}
        body {{ font-family: 'Segoe UI', sans-serif; background: #0f0f23; color: #e0e0e0; padding: 20px; }}
        h1 {{ color: #7c3aed; margin-bottom: 10px; font-size: 24px; }}
        .stats {{
            background: #1a1a3e; padding: 15px 20px; border-radius: 12px;
            margin-bottom: 20px; display: flex; gap: 30px; flex-wrap: wrap;
        }}
        .stat {{ text-align: center; }}
        .stat-value {{ font-size: 28px; font-weight: bold; color: #7c3aed; }}
        .stat-label {{ font-size: 12px; color: #888; }}
        .copy-section {{
            background: #1a1a3e; border-radius: 12px; padding: 20px; margin-bottom: 20px;
        }}
        .copy-section h2 {{ color: #7c3aed; margin-bottom: 10px; font-size: 18px; }}
        .copy-btn {{
            background: #7c3aed; color: white; border: none; padding: 12px 24px;
            border-radius: 8px; cursor: pointer; font-size: 16px; font-weight: bold;
            margin-bottom: 15px; margin-right: 10px;
        }}
        .copy-btn:hover {{ background: #6d28d9; }}
        .copy-btn.copied {{ background: #22c55e; }}
        .links-box {{
            background: #0a0a1a; border: 1px solid #333; border-radius: 8px;
            padding: 15px; max-height: 300px; overflow-y: auto;
            font-family: monospace; font-size: 13px; line-height: 1.8;
            white-space: pre-wrap; word-break: break-all; user-select: all;
        }}
        .video-table {{ width: 100%; border-collapse: collapse; margin-top: 20px; }}
        .video-table th {{
            background: #1a1a3e; color: #7c3aed; padding: 10px; text-align: left;
            position: sticky; top: 0; z-index: 1;
        }}
        .video-table td {{ padding: 8px 10px; border-bottom: 1px solid #222; font-size: 13px; }}
        .video-table tr:hover {{ background: #1a1a2e; }}
        .views {{ color: #22c55e; font-weight: bold; }}
        .duration {{ color: #f59e0b; }}
        a {{ color: #818cf8; text-decoration: none; }}
        a:hover {{ text-decoration: underline; }}
        .filter-bar {{
            background: #1a1a3e; padding: 15px; border-radius: 12px;
            margin-bottom: 20px; display: flex; gap: 15px; align-items: center; flex-wrap: wrap;
        }}
        .filter-bar label {{ font-size: 13px; color: #888; }}
        .filter-bar select, .filter-bar input {{
            background: #0a0a1a; color: #e0e0e0; border: 1px solid #333;
            padding: 6px 10px; border-radius: 6px;
        }}
    </style>
</head>
<body>
    <h1>Construction Timelapse - Viral Videos</h1>
    <p style="color:#888; margin-bottom:20px;">Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')} | Credits: ~{credits_used} | Creators: {unique_creators}</p>

    <div class="stats">
        <div class="stat"><div class="stat-value">{len(sorted_videos)}</div><div class="stat-label">Videos</div></div>
        <div class="stat"><div class="stat-value">{unique_creators}</div><div class="stat-label">Creators</div></div>
        <div class="stat"><div class="stat-value">{total_views/1e9:.1f}B</div><div class="stat-label">Total Views</div></div>
        <div class="stat"><div class="stat-value">{sorted_videos[0]['views']/1e6:.0f}M</div><div class="stat-label">Top Video</div></div>
    </div>

    <div class="copy-section">
        <h2>Links para Download em Massa</h2>
        <button class="copy-btn" onclick="copyLinks(this)">COPIAR TODOS OS {len(all_links)} LINKS</button>
        <button class="copy-btn" style="background:#059669;" onclick="copySelected(this)">Copiar Selecionados</button>
        <div class="links-box" id="all-links">{chr(10).join(all_links)}</div>
    </div>

    <div class="filter-bar">
        <label>Min Views:</label>
        <select id="filterViews" onchange="filterTable()">
            <option value="1000000">1M+</option>
            <option value="5000000">5M+</option>
            <option value="10000000">10M+</option>
            <option value="50000000">50M+</option>
        </select>
        <label>Creator:</label>
        <input type="text" id="filterCreator" placeholder="@username" oninput="filterTable()">
        <label>Descricao:</label>
        <input type="text" id="filterDesc" placeholder="keyword" oninput="filterTable()">
        <span id="filterCount" style="color:#7c3aed;font-weight:bold;margin-left:10px;"></span>
    </div>

    <table class="video-table" id="videoTable">
        <thead><tr>
            <th><input type="checkbox" id="selectAll" onchange="toggleAll(this)"></th>
            <th>#</th><th>Creator</th><th>Views</th><th>Likes</th><th>Duration</th><th>Description</th><th>Link</th>
        </tr></thead>
        <tbody>
"""

    for i, v in enumerate(sorted_videos, 1):
        views_str = f"{v['views']/1e6:.1f}M"
        likes_str = f"{v['likes']/1e6:.1f}M" if v['likes'] >= 1e6 else f"{v['likes']/1e3:.0f}K"
        desc_safe = v['description'].replace('&', '&amp;').replace('"', '&quot;').replace('<', '&lt;').replace('>', '&gt;')
        url_safe = v['url'].replace('&', '&amp;').replace('"', '&quot;')

        html += f"""            <tr data-views="{v['views']}" data-creator="{v['username']}" data-desc="{desc_safe.lower()}" data-url="{v['url']}">
                <td><input type="checkbox" class="vid-check" data-url="{v['url']}"></td>
                <td>{i}</td>
                <td>@{v['username']}</td>
                <td class="views">{views_str}</td>
                <td>{likes_str}</td>
                <td class="duration">{v['duration_s']}s</td>
                <td title="{desc_safe}">{desc_safe[:80]}</td>
                <td><a href="{url_safe}" target="_blank">Abrir</a></td>
            </tr>
"""

    html += """        </tbody>
    </table>

    <script>
        function copyLinks(btn) {
            const text = document.getElementById('all-links').textContent;
            navigator.clipboard.writeText(text).then(() => {
                btn.textContent = 'COPIADO!';
                btn.classList.add('copied');
                setTimeout(() => { btn.textContent = 'COPIAR TODOS OS """ + str(len(all_links)) + """ LINKS'; btn.classList.remove('copied'); }, 2000);
            });
        }
        function copySelected(btn) {
            const checks = document.querySelectorAll('.vid-check:checked');
            const urls = Array.from(checks).map(c => c.dataset.url).join('\\n');
            if (!urls) { alert('Selecione pelo menos um video!'); return; }
            navigator.clipboard.writeText(urls).then(() => {
                btn.textContent = checks.length + ' COPIADOS!';
                btn.classList.add('copied');
                setTimeout(() => { btn.textContent = 'Copiar Selecionados'; btn.classList.remove('copied'); }, 2000);
            });
        }
        function toggleAll(cb) {
            document.querySelectorAll('.vid-check').forEach(c => {
                if (c.closest('tr').style.display !== 'none') c.checked = cb.checked;
            });
        }
        function filterTable() {
            const minV = parseInt(document.getElementById('filterViews').value);
            const cr = document.getElementById('filterCreator').value.toLowerCase().replace('@','');
            const desc = document.getElementById('filterDesc').value.toLowerCase();
            let count = 0;
            document.querySelectorAll('#videoTable tbody tr').forEach(row => {
                const show = parseInt(row.dataset.views) >= minV &&
                    (!cr || row.dataset.creator.includes(cr)) &&
                    (!desc || row.dataset.desc.includes(desc));
                row.style.display = show ? '' : 'none';
                if (show) count++;
            });
            document.getElementById('filterCount').textContent = count + ' videos';
        }
        filterTable();
    </script>
</body>
</html>"""

    output_path = "/home/glauko/viral-social/data/construction_timelapse_videos.html"
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(html)

    json_path = "/home/glauko/viral-social/data/construction_timelapse_videos.json"
    with open(json_path, "w", encoding="utf-8") as f:
        json.dump({
            "generated": datetime.now().isoformat(),
            "total_videos": len(sorted_videos),
            "total_creators": unique_creators,
            "credits_used": credits_used,
            "videos": sorted_videos,
        }, f, indent=2, ensure_ascii=False)

    print(f"\n{'='*70}")
    print(f"DONE!")
    print(f"  Videos: {len(sorted_videos)}")
    print(f"  Creators: {unique_creators}")
    print(f"  Total views: {total_views/1e9:.1f}B")
    print(f"  Credits used: ~{credits_used}")
    print(f"  HTML: {output_path}")
    print(f"  JSON: {json_path}")
    print(f"{'='*70}")

    print(f"\nTOP 20:")
    for i, v in enumerate(sorted_videos[:20], 1):
        print(f"  {i}. @{v['username']}: {v['views']/1e6:.1f}M views | {v['duration_s']}s | {v['description'][:50]}")


if __name__ == "__main__":
    main()
