#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
밍글 스튜디오 Discord 문의 자동 삭제 봇
- 지정된 채널의 메시지를 7일 후 자동 삭제
- 개인정보보호법(PIPA) 준수를 위한 데이터 보관기간 관리
"""

import os
import sys
import json
import urllib.request
import ssl
import time
from datetime import datetime, timedelta, timezone

# ─── 설정 ───────────────────────────────────────
BOT_TOKEN = ''
CHANNEL_ID = ''
DELETE_AFTER_DAYS = 7
CHECK_INTERVAL_HOURS = 6  # 삭제 체크 주기 (시간)

def load_env():
    """Load .env file from parent directory"""
    global BOT_TOKEN, CHANNEL_ID, DELETE_AFTER_DAYS, CHECK_INTERVAL_HOURS

    env_paths = [
        os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '.env'),
        os.path.join(os.path.dirname(os.path.abspath(__file__)), '.env'),
    ]

    for env_path in env_paths:
        if os.path.exists(env_path):
            with open(env_path, 'r', encoding='utf-8') as f:
                for line in f:
                    line = line.strip()
                    if line and not line.startswith('#') and '=' in line:
                        key, value = line.split('=', 1)
                        key = key.strip()
                        value = value.strip().strip('"').strip("'")
                        if key == 'DISCORD_BOT_TOKEN':
                            BOT_TOKEN = value
                        elif key == 'DISCORD_INQUIRY_CHANNEL_ID':
                            CHANNEL_ID = value
                        elif key == 'DELETE_AFTER_DAYS':
                            DELETE_AFTER_DAYS = int(value)
                        elif key == 'CHECK_INTERVAL_HOURS':
                            CHECK_INTERVAL_HOURS = int(value)
            break

def discord_api(method, endpoint, data=None):
    """Discord API 호출"""
    url = f'https://discord.com/api/v10{endpoint}'
    headers = {
        'Authorization': f'Bot {BOT_TOKEN}',
        'Content-Type': 'application/json',
    }

    body = json.dumps(data).encode('utf-8') if data else None
    req = urllib.request.Request(url, data=body, headers=headers, method=method)

    ctx = ssl.create_default_context()
    try:
        with urllib.request.urlopen(req, context=ctx, timeout=15) as resp:
            if resp.status == 204:
                return None
            return json.loads(resp.read().decode('utf-8'))
    except urllib.error.HTTPError as e:
        error_body = e.read().decode('utf-8') if e.fp else ''
        print(f"[ERROR] Discord API {method} {endpoint}: {e.code} {error_body}")

        # Rate limit 처리
        if e.code == 429:
            retry_data = json.loads(error_body) if error_body else {}
            retry_after = retry_data.get('retry_after', 5)
            print(f"[RATE LIMIT] Waiting {retry_after}s...")
            time.sleep(retry_after + 0.5)
            return discord_api(method, endpoint, data)

        raise

def get_old_messages():
    """지정 채널에서 만료된 메시지 조회"""
    cutoff = datetime.now(timezone.utc) - timedelta(days=DELETE_AFTER_DAYS)
    old_messages = []
    last_id = None

    while True:
        params = f'?limit=100'
        if last_id:
            params += f'&before={last_id}'

        messages = discord_api('GET', f'/channels/{CHANNEL_ID}/messages{params}')

        if not messages:
            break

        for msg in messages:
            # Discord 타임스탬프 파싱
            msg_time = datetime.fromisoformat(msg['timestamp'].replace('+00:00', '+00:00'))
            if msg_time.tzinfo is None:
                msg_time = msg_time.replace(tzinfo=timezone.utc)

            if msg_time < cutoff:
                old_messages.append({
                    'id': msg['id'],
                    'timestamp': msg['timestamp'],
                    'content': msg.get('content', '')[:50]
                })

        last_id = messages[-1]['id']

        # 가장 오래된 메시지도 만료 기간 내라면 더 조회할 필요 없음
        oldest_time = datetime.fromisoformat(messages[-1]['timestamp'].replace('+00:00', '+00:00'))
        if oldest_time.tzinfo is None:
            oldest_time = oldest_time.replace(tzinfo=timezone.utc)
        if oldest_time >= cutoff:
            continue
        else:
            break

        time.sleep(0.5)  # Rate limit 방지

    return old_messages

def delete_messages(messages):
    """메시지 삭제"""
    deleted = 0
    for msg in messages:
        try:
            discord_api('DELETE', f'/channels/{CHANNEL_ID}/messages/{msg["id"]}')
            print(f"  [DELETE] {msg['id']} ({msg['timestamp'][:10]})")
            deleted += 1
            time.sleep(0.5)  # Rate limit 방지
        except Exception as e:
            print(f"  [ERROR] Failed to delete {msg['id']}: {e}")
    return deleted

def run_cleanup():
    """한 번의 정리 사이클 실행"""
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print(f"\n[{now}] Cleanup check started (delete after {DELETE_AFTER_DAYS} days)")

    try:
        messages = get_old_messages()

        if messages:
            print(f"  Found {len(messages)} expired message(s)")
            deleted = delete_messages(messages)
            print(f"  Deleted {deleted}/{len(messages)} message(s)")
        else:
            print(f"  No expired messages found")

    except Exception as e:
        print(f"  [ERROR] Cleanup failed: {e}")

def main():
    """메인 실행"""
    load_env()

    if not BOT_TOKEN:
        print("Error: DISCORD_BOT_TOKEN not set in .env")
        sys.exit(1)
    if not CHANNEL_ID:
        print("Error: DISCORD_CHANNEL_ID not set in .env")
        sys.exit(1)

    print("Mingle Studio Discord Cleanup Bot")
    print("=" * 40)
    print(f"Channel ID: {CHANNEL_ID}")
    print(f"Delete after: {DELETE_AFTER_DAYS} days")
    print(f"Check interval: {CHECK_INTERVAL_HOURS} hours")
    print("=" * 40)

    # 봇 정보 확인
    try:
        bot_info = discord_api('GET', '/users/@me')
        print(f"Bot: {bot_info['username']}#{bot_info.get('discriminator', '0')}")
    except Exception as e:
        print(f"Error: Failed to connect to Discord: {e}")
        sys.exit(1)

    print("Bot started. Press Ctrl+C to stop.\n")

    try:
        while True:
            run_cleanup()
            print(f"  Next check in {CHECK_INTERVAL_HOURS} hours...")
            time.sleep(CHECK_INTERVAL_HOURS * 3600)
    except KeyboardInterrupt:
        print("\nBot stopped.")


if __name__ == '__main__':
    main()
