"""
Fetch raw Slack history for FAQ corpus refresh.

Usage:
    python tools/fetch_slack.py

Required env vars (set in .env or environment):
    SLACK_BOT_TOKEN     xoxb-... bot token (needs channels:history, channels:read scopes)
    SLACK_SWEEP_DAYS    How many days back to fetch (default: 30)

Output:
    tools/.slack_raw.json  — consumed by extract_qa.py
"""

import json
import logging
import os
import sys
import time
from datetime import datetime, timedelta, timezone
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent))

from dotenv import load_dotenv
load_dotenv(Path(__file__).parent.parent / ".env")

from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("fetch_slack")

SLACK_BOT_TOKEN = os.environ["SLACK_BOT_TOKEN"]
SWEEP_DAYS = int(os.environ.get("SLACK_SWEEP_DAYS", "30"))
CHANNELS_FILE = Path(__file__).parent.parent / "channels.json"
RAW_OUTPUT = Path(__file__).parent / ".slack_raw.json"

OLDEST_TS = str((datetime.now(timezone.utc) - timedelta(days=SWEEP_DAYS)).timestamp())
client = WebClient(token=SLACK_BOT_TOKEN)


def load_channels() -> list[dict]:
    with open(CHANNELS_FILE, encoding="utf-8") as f:
        return json.load(f)


def fetch_messages(channel_id: str) -> list[dict]:
    messages = []
    cursor = None
    while True:
        try:
            resp = client.conversations_history(
                channel=channel_id,
                oldest=OLDEST_TS,
                limit=200,
                cursor=cursor,
            )
        except SlackApiError as exc:
            err = exc.response.get("error", "")
            if err == "ratelimited":
                wait = int(exc.response.headers.get("Retry-After", 10))
                log.warning("Rate limited — waiting %ds", wait)
                time.sleep(wait)
                continue
            log.warning("Skipping channel %s: %s", channel_id, err)
            return []

        for msg in resp.get("messages", []):
            if msg.get("type") != "message" or msg.get("subtype"):
                continue
            # inline thread replies so extract_qa.py has everything in one file
            if msg.get("reply_count", 0) > 0:
                try:
                    thread_resp = client.conversations_replies(
                        channel=channel_id,
                        ts=msg["ts"],
                        oldest=OLDEST_TS,
                        limit=200,
                    )
                    msg["replies"] = thread_resp.get("messages", [])[1:]
                    time.sleep(0.3)
                except SlackApiError:
                    msg["replies"] = []
            messages.append(msg)

        cursor = (resp.get("response_metadata") or {}).get("next_cursor")
        if not cursor:
            break
        time.sleep(0.5)

    return messages


def run():
    # skip defer_all channels — the bot never monitors them
    channels = [c for c in load_channels() if not c.get("defer_all")]
    log.info("Fetching %d channels (SWEEP_DAYS=%d)", len(channels), SWEEP_DAYS)

    result = {}
    for ch in channels:
        cid, cname = ch["id"], ch["name"]
        log.info("Fetching #%s (%s)", cname, cid)
        messages = fetch_messages(cid)
        log.info("  %d messages in #%s", len(messages), cname)
        result[cname] = {"id": cid, "messages": messages}
        time.sleep(0.5)

    RAW_OUTPUT.write_text(json.dumps(result, indent=2), encoding="utf-8")
    log.info("Saved raw history → %s", RAW_OUTPUT)


if __name__ == "__main__":
    run()
