#!/usr/bin/env python3
"""Send the actual photo/video of an approved fan news queue item."""

import asyncio
import re
import sys
import tempfile
from pathlib import Path

from telethon import TelegramClient

import fan_news_collector as collector
import telegram_publisher as publisher


def caption_from_source(text, channel_username):
    # Telegram source handles are collection metadata, not news attribution.
    text = re.sub(r'(?<!\w)@[A-Za-z0-9_]{5,32}', '', text or '')
    text = re.sub(r'[ \t]+', ' ', text)
    lines = [
        line.strip() for line in text.splitlines()
        if re.search(r'\w', line, re.UNICODE)
    ]
    body = '\n'.join(lines).strip()
    username = str(channel_username or '').strip().lstrip('@')

    if not body:
        raise RuntimeError('Source caption is empty after removing handles.')
    if not re.fullmatch(r'[A-Za-z0-9_]{5,32}', username):
        raise RuntimeError('Destination username is invalid.')

    caption = '⚽️ ' + body + '\n\n@' + username

    if len(caption) > 1024:
        raise RuntimeError('Media caption exceeds Telegram limit.')

    return caption


def load_feed(db, feed_id):
    with db.cursor() as cursor:
        cursor.execute("""
            SELECT f.id AS feed_id, f.source_message_id,
                   f.text_content, f.has_media,
                   s.username AS source_username
            FROM fan_news_feed_items f
            JOIN sources s ON s.id = f.source_id
            WHERE f.id = %s
            LIMIT 1
        """, (feed_id,))
        return cursor.fetchone()


def load_queue(db, queue_id):
    with db.cursor() as cursor:
        cursor.execute("""
            SELECT q.id AS queue_id, q.status AS queue_status,
                   p.status AS post_status, f.id AS feed_id,
                   f.source_message_id, f.text_content, f.has_media,
                   s.username AS source_username,
                   c.id AS channel_id, c.username AS channel_username,
                   c.publisher_id, c.is_active, c.auto_publish
            FROM publish_queue q
            JOIN posts p ON p.id = q.post_id
            JOIN channels c ON c.id = q.channel_id
            JOIN fan_news_review_queue r
              ON r.channel_id = q.channel_id
             AND p.dedupe_hash =
                 SHA2(CONCAT('fan_news:', r.feed_item_id,
                             ':channel:', r.channel_id), 256)
            JOIN fan_news_feed_items f ON f.id = r.feed_item_id
            JOIN sources s ON s.id = f.source_id
            WHERE q.id = %s
              AND c.channel_type = 'football_fan'
            LIMIT 1
        """, (queue_id,))
        return cursor.fetchone()


async def execute(mode, item_id):
    db = publisher.get_database()
    reader = None
    sender = None

    try:
        row = load_feed(db, item_id) if mode == 'preview' else load_queue(db, item_id)

        if not row:
            raise RuntimeError('Fan feed or queue mapping not found.')
        if int(row['has_media'] or 0) != 1:
            raise RuntimeError('Original message has no media.')
        if not row.get('source_username'):
            raise RuntimeError('Source Telegram username is missing.')

        if mode == 'run':
            if row['queue_status'] != 'queued' or row['post_status'] != 'approved':
                raise RuntimeError('Queue is not approved and queued.')
            if int(row['is_active'] or 0) != 1 or int(row['auto_publish'] or 0) != 1:
                raise RuntimeError('Destination channel is inactive.')

            publisher_id = int(row['publisher_id'])
            channel_id = int(row['channel_id'])
            pub = publisher.get_publisher(db, publisher_id)
            channel = publisher.get_channel(db, channel_id)
            publisher.validate_assignment(publisher_id, pub, channel)

        # Use the existing reader session to fetch the original Telegram message.
        collector.ensure_session_copy()

        if mode == 'run':
            api_id = int(str(pub['telegram_api_id']).strip())
            api_hash = str(pub['telegram_api_hash']).strip()
        else:
            with db.cursor() as cursor:
                cursor.execute("""
                    SELECT telegram_api_id, telegram_api_hash
                    FROM publishers
                    WHERE is_active = 1
                    ORDER BY id LIMIT 1
                """)
                credentials = cursor.fetchone()
            if not credentials:
                raise RuntimeError('No active Telegram credentials.')
            api_id = int(str(credentials['telegram_api_id']).strip())
            api_hash = str(credentials['telegram_api_hash']).strip()

        reader = TelegramClient(
            str(collector.FAN_SESSION.with_suffix('')), api_id, api_hash
        )
        await reader.connect()

        if not await reader.is_user_authorized():
            raise RuntimeError('Fan reader session is not authorized.')

        source = await reader.get_entity(
            '@' + str(row['source_username']).lstrip('@')
        )
        message = await reader.get_messages(
            source, ids=int(row['source_message_id'])
        )

        if message is None:
            raise RuntimeError('Original Telegram message is unavailable.')

        if message.video:
            media_type = 'video'
        elif message.photo:
            media_type = 'photo'
        else:
            raise RuntimeError('Media is not a supported video or photo.')

        if mode == 'preview':
            print(
                f"MEDIA_PREVIEW feed={row['feed_id']} "
                f"type={media_type} source_message={message.id}"
            )
            print('Original text:', message.message or '')
            print('PREVIEW ONLY - NOTHING SENT')
            return

        caption = caption_from_source(
            row['text_content'], row['channel_username']
        )

        sender = publisher.build_client(publisher_id, pub)
        await publisher.ensure_authorized(db, publisher_id, sender)
        target = publisher.resolve_target(channel)

        with tempfile.TemporaryDirectory(prefix='fan_news_media_') as directory:
            file_path = await reader.download_media(
                message, file=str(Path(directory) / 'original')
            )
            if not file_path or not Path(file_path).is_file():
                raise RuntimeError('Media download failed.')

            sent = await sender.send_file(
                target,
                file_path,
                caption=caption,
                supports_streaming=(media_type == 'video'),
            )

        print(f"SEND_FILE_SUCCESS message_id={sent.id}")

    finally:
        if sender is not None:
            await sender.disconnect()
        if reader is not None:
            await reader.disconnect()
        db.close()


if __name__ == '__main__':
    if len(sys.argv) != 3 or sys.argv[1] not in ('preview', 'run'):
        raise SystemExit(
            'Usage: python3 fan_news_media_sender.py preview FEED_ID | run QUEUE_ID'
        )
    try:
        item_id = int(sys.argv[2])
        if item_id < 1:
            raise ValueError('ID must be positive.')
        asyncio.run(execute(sys.argv[1], item_id))
    except Exception as exc:
        print(f'MEDIA_ERROR: {type(exc).__name__}: {exc}', file=sys.stderr)
        raise SystemExit(1)
