"""OMEGA Telegram bot starter. Supports ticket intake and staff ticket replies."""
import asyncio, os, secrets
from uuid import uuid4
from datetime import datetime, timezone
from aiogram import Bot, Dispatcher, F
from aiogram.filters import CommandStart, Command
from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
from sqlalchemy import text

TOKEN = os.getenv("TELEGRAM_BOT_TOKEN", "")
DB_URL = os.getenv("DATABASE_URL", "postgresql+asyncpg://omega:omega@localhost:5432/omega")
OWNER_IDS = {x.strip() for x in os.getenv("OWNER_TELEGRAM_IDS", "").split(",") if x.strip()}
engine = create_async_engine(DB_URL, pool_pre_ping=True)
Session = async_sessionmaker(engine, expire_on_commit=False)
bot = Bot(TOKEN) if TOKEN else None
dp = Dispatcher()

@dp.message(CommandStart())
async def start(message: Message):
    keyboard = InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text="🎫 Create support ticket", callback_data="new_ticket")]])
    await message.answer("🌌 OMEGA Support\n\nCreate a ticket and our team will follow up here. Do not send passwords, card data, or private keys.", reply_markup=keyboard)

@dp.callback_query(F.data == "new_ticket")
async def new_ticket(callback: CallbackQuery):
    await callback.message.answer("Send your issue as one message. Format: category | subject | details\nExample: Billing | Invoice issue | Please help me understand my invoice.")
    await callback.answer()

@dp.message(Command("mytickets"))
async def my_tickets(message: Message):
    async with Session() as db:
        rows = (await db.execute(text("SELECT public_id, subject, status FROM tickets WHERE user_id IN (SELECT id FROM users WHERE telegram_id=:tg) ORDER BY created_at DESC LIMIT 10"), {"tg": str(message.from_user.id)})).all()
    if not rows:
        await message.answer("No linked tickets found yet. Create a ticket from the menu."); return
    await message.answer("\n".join(f"{r.public_id} · {r.status} · {r.subject}" for r in rows))

@dp.message(F.text)
async def text_handler(message: Message):
    if not message.from_user or not message.text: return
    # Staff command: /reply OMEGA-ID text. Staff authorization comes from DB role, never username.
    if message.text.startswith("/reply "):
        parts = message.text.split(" ", 2)
        if len(parts) < 3:
            await message.answer("Usage: /reply OMEGA-ID your response"); return
        public_id, body = parts[1], parts[2]
        async with Session() as db:
            staff = (await db.execute(text("SELECT id, role FROM users WHERE telegram_id=:tg AND is_active=true"), {"tg": str(message.from_user.id)})).first()
            if not staff or staff.role not in ("OWNER", "SUPERVISOR", "MANAGER"):
                await message.answer("Your Telegram ID is not linked to an active staff account."); return
            ticket = (await db.execute(text("SELECT id, user_id FROM tickets WHERE public_id=:pid"), {"pid": public_id})).first()
            if not ticket:
                await message.answer("Ticket not found."); return
            await db.execute(text("INSERT INTO ticket_messages (id,ticket_id,sender_id,sender_role,body,is_internal,created_at) VALUES (:id,:tid,:sid,:role,:body,false,:now)"),
                {"id": str(uuid4()), "tid": ticket.id, "sid": staff.id, "role": staff.role, "body": body, "now": datetime.now(timezone.utc)})
            await db.execute(text("UPDATE tickets SET status='IN_PROGRESS', assignee_id=:sid, updated_at=:now WHERE id=:tid"), {"sid": staff.id, "now": datetime.now(timezone.utc), "tid": ticket.id})
            await db.commit()
            customer = (await db.execute(text("SELECT telegram_id FROM users WHERE id=:uid"), {"uid": ticket.user_id})).scalar_one_or_none()
        if customer:
            try: await bot.send_message(int(customer), f"Support update for {public_id}:\n\n{body}")
            except Exception: pass
        await message.answer(f"Reply recorded for {public_id}."); return

    # User intake: first contact creates a minimal user record if needed, then a ticket.
    chunks = [x.strip() for x in message.text.split("|", 2)]
    category = chunks[0].upper()[:40] if len(chunks) == 3 else "GENERAL"
    subject = chunks[1][:200] if len(chunks) == 3 else "Telegram support request"
    body = chunks[2][:10000] if len(chunks) == 3 else message.text[:10000]
    async with Session() as db:
        user = (await db.execute(text("SELECT id FROM users WHERE telegram_id=:tg"), {"tg": str(message.from_user.id)})).first()
        if not user:
            # No password login is enabled for Telegram-only users until they complete account linking.
            user_id = str(uuid4())
            await db.execute(text("INSERT INTO users (id,username,password_hash,role,telegram_id,is_active,created_at) VALUES (:id,:username,:hash,'USER',:tg,true,:now)"),
                {"id": user_id, "username": f"tg_{message.from_user.id}", "hash": secrets.token_urlsafe(48), "tg": str(message.from_user.id), "now": datetime.now(timezone.utc)})
        else: user_id = user.id
        ticket_id = str(uuid4()); public_id = "OMG-" + secrets.token_hex(4).upper(); now = datetime.now(timezone.utc)
        await db.execute(text("INSERT INTO tickets (id,public_id,user_id,category,priority,status,subject,created_at,updated_at) VALUES (:id,:pid,:uid,:cat,'P3','OPEN',:sub,:now,:now)"),
            {"id": ticket_id, "pid": public_id, "uid": user_id, "cat": category, "sub": subject, "now": now})
        await db.execute(text("INSERT INTO ticket_messages (id,ticket_id,sender_id,sender_role,body,is_internal,created_at) VALUES (:id,:tid,:uid,'USER',:body,false,:now)"),
            {"id": str(uuid4()), "tid": ticket_id, "uid": user_id, "body": body, "now": now})
        await db.commit()
    await message.answer(f"Ticket created: {public_id}\nCategory: {category}\nOur support team will reply here. Use /mytickets to check linked tickets.")

async def main():
    if not TOKEN:
        raise RuntimeError("TELEGRAM_BOT_TOKEN is required to start the bot container")
    await dp.start_polling(bot)

if __name__ == "__main__": asyncio.run(main())
