import httpx
import hmac
import hashlib
import secrets
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import and_
from pydantic import BaseModel

from app.db.session import get_db
from app.db.models import User, TelegramBot, TenantSettings, Customer
from app.api.deps import get_current_user
from app.core.config import get_settings
from app.utils.encryption import encrypt_token, decrypt_token, generate_webhook_secret


router = APIRouter()
settings = get_settings()


class CheckTokenRequest(BaseModel):
    bot_token: str


class CheckTokenResponse(BaseModel):
    ok: bool
    username: str | None = None
    error: str | None = None


class SetWebhookRequest(BaseModel):
    bot_token: str


class SetWebhookResponse(BaseModel):
    ok: bool
    username: str | None = None
    webhook_url: str | None = None
    error: str | None = None


class DeeplinkResponse(BaseModel):
    deeplink: str
    qr_data: str
    username: str


class SendTestResponse(BaseModel):
    success: bool
    message: str
    error: str | None = None


class ChannelTestRequest(BaseModel):
    channel: str  # telegram, email, vk
    recipient: str  # chat_id, email, vk_user_id
    message: str


class ChannelTestResponse(BaseModel):
    success: bool
    message: str
    error: str | None = None


async def _check_telegram_bot(bot_token: str) -> dict:
    """Проверить токен бота через Telegram API"""
    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"https://api.telegram.org/bot{bot_token}/getMe",
                timeout=10.0
            )
            
            if response.status_code == 200:
                data = response.json()
                if data.get("ok"):
                    return {
                        "ok": True,
                        "username": data["result"].get("username"),
                        "first_name": data["result"].get("first_name"),
                        "id": data["result"].get("id")
                    }
                else:
                    error_desc = data.get("description", "Unknown error")
                    return {"ok": False, "error": f"Telegram API error: {error_desc}"}
            else:
                try:
                    error_data = response.json()
                    error_desc = error_data.get("description", f"HTTP {response.status_code}")
                except:
                    error_desc = f"HTTP {response.status_code}"
                return {"ok": False, "error": f"Ошибка подключения к Telegram API: {error_desc}"}
                
    except httpx.TimeoutException:
        return {"ok": False, "error": "Превышено время ожидания ответа от Telegram API. Проверьте интернет-соединение."}
    except httpx.ConnectError:
        return {"ok": False, "error": "Не удалось подключиться к Telegram API. Проверьте интернет-соединение."}
    except Exception as e:
        return {"ok": False, "error": f"Ошибка проверки токена: {str(e)}"}


@router.post("/check-token", response_model=CheckTokenResponse)
async def check_telegram_token(
    request: CheckTokenRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Проверить токен Telegram бота"""
    result = await _check_telegram_bot(request.bot_token)
    
    if result["ok"]:
        return CheckTokenResponse(
            ok=True,
            username=result["username"]
        )
    else:
        return CheckTokenResponse(
            ok=False,
            error=result["error"]
        )


@router.post("/set-webhook", response_model=SetWebhookResponse)
async def set_telegram_webhook(
    request: SetWebhookRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Установить webhook для бренд-бота"""
    
    # Проверяем токен
    bot_info = await _check_telegram_bot(request.bot_token)
    if not bot_info.get("ok"):
        error_msg = bot_info.get("error", "Неизвестная ошибка при проверке токена")
        return SetWebhookResponse(
            ok=False,
            error=error_msg
        )
    
    # Генерируем webhook secret
    webhook_secret = generate_webhook_secret()
    
    # Создаем webhook URL
    webhook_url = f"{settings.TG_WEBHOOK_BASE}/webhook/{current_user.tenant_id}?secret={webhook_secret}"
    
    # Устанавливаем webhook через Telegram API
    try:
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"https://api.telegram.org/bot{request.bot_token}/setWebhook",
                json={"url": webhook_url},
                timeout=10.0
            )
            
            if response.status_code != 200:
                return SetWebhookResponse(
                    ok=False,
                    error=f"Failed to set webhook: HTTP {response.status_code}"
                )
            
            webhook_result = response.json()
            if not webhook_result.get("ok"):
                return SetWebhookResponse(
                    ok=False,
                    error=f"Telegram API error: {webhook_result.get('description')}"
                )
    
    except Exception as e:
        return SetWebhookResponse(
            ok=False,
            error=f"Failed to set webhook: {str(e)}"
        )
    
    # Сохраняем/обновляем бота в БД
    try:
        encrypted_token = encrypt_token(request.bot_token)
        
        # Проверяем существующего бота
        existing_bot = db.query(TelegramBot).filter(
            TelegramBot.tenant_id == current_user.tenant_id
        ).first()
        
        if existing_bot:
            existing_bot.bot_token_enc = encrypted_token
            existing_bot.username = bot_info.get("username")
            existing_bot.webhook_secret = webhook_secret
            existing_bot.status = "active"
            existing_bot.updated_at = datetime.utcnow()
        else:
            bot = TelegramBot(
                tenant_id=current_user.tenant_id,
                bot_token_enc=encrypted_token,
                username=bot_info.get("username"),
                webhook_secret=webhook_secret,
                status="active"
            )
            db.add(bot)
        
        # Обновляем настройки тенанта
        settings_record = db.query(TenantSettings).filter(
            TenantSettings.tenant_id == current_user.tenant_id
        ).first()
        
        if settings_record:
            settings_record.tg_sender = "brand"
            settings_record.updated_at = datetime.utcnow()
        else:
            settings_record = TenantSettings(
                tenant_id=current_user.tenant_id,
                tg_sender="brand"
            )
            db.add(settings_record)
        
        db.commit()
        
        return SetWebhookResponse(
            ok=True,
            username=bot_info.get("username"),
            webhook_url=webhook_url
        )
    except Exception as e:
        db.rollback()
        return SetWebhookResponse(
            ok=False,
            error=f"Ошибка сохранения бота в БД: {str(e)}"
        )


@router.post("/disable-brand")
async def disable_brand_bot(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Отключить бренд-бот и вернуться к системному"""
    
    # Находим бота тенанта
    bot = db.query(TelegramBot).filter(
        TelegramBot.tenant_id == current_user.tenant_id
    ).first()
    
    if bot:
        # Удаляем webhook
        try:
            decrypted_token = decrypt_token(bot.bot_token_enc)
            if decrypted_token:
                async with httpx.AsyncClient() as client:
                    await client.post(
                        f"https://api.telegram.org/bot{decrypted_token}/deleteWebhook",
                        timeout=10.0
                    )
        except Exception:
            pass  # Игнорируем ошибки при удалении webhook
        
        # Деактивируем бота
        bot.status = "disabled"
        bot.updated_at = datetime.utcnow()
    
    # Возвращаемся к системному боту
    settings_record = db.query(TenantSettings).filter(
        TenantSettings.tenant_id == current_user.tenant_id
    ).first()
    
    if settings_record:
        settings_record.tg_sender = "system"
        settings_record.updated_at = datetime.utcnow()
    else:
        settings_record = TenantSettings(
            tenant_id=current_user.tenant_id,
            tg_sender="system"
        )
        db.add(settings_record)
    
    db.commit()
    
    return {"ok": True, "message": "Brand bot disabled, switched to system bot"}


@router.post("/enable-brand")
async def enable_brand_bot(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Активировать бренд-бот (если он уже настроен)"""
    
    # Проверяем наличие активного бренд-бота
    bot = db.query(TelegramBot).filter(
        and_(
            TelegramBot.tenant_id == current_user.tenant_id,
            TelegramBot.status == "active"
        )
    ).first()
    
    if not bot:
        raise HTTPException(
            status_code=400,
            detail="Бренд-бот не настроен. Сначала добавьте бота через /telegram/set-webhook"
        )
    
    # Обновляем настройки тенанта
    settings_record = db.query(TenantSettings).filter(
        TenantSettings.tenant_id == current_user.tenant_id
    ).first()
    
    if settings_record:
        settings_record.tg_sender = "brand"
        settings_record.updated_at = datetime.utcnow()
    else:
        settings_record = TenantSettings(
            tenant_id=current_user.tenant_id,
            tg_sender="brand"
        )
        db.add(settings_record)
    
    db.commit()
    
    return {"ok": True, "message": "Brand bot enabled", "username": bot.username}


@router.post("/disable-telegram")
async def disable_telegram(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Полностью отключить Telegram для тенанта (не использовать в рассылках)"""
    
    # Обновляем настройки тенанта
    settings_record = db.query(TenantSettings).filter(
        TenantSettings.tenant_id == current_user.tenant_id
    ).first()
    
    if settings_record:
        settings_record.tg_sender = "disabled"
        settings_record.updated_at = datetime.utcnow()
    else:
        settings_record = TenantSettings(
            tenant_id=current_user.tenant_id,
            tg_sender="disabled"
        )
        db.add(settings_record)
    
    db.commit()
    
    return {"ok": True, "message": "Telegram disabled for this tenant"}


def _generate_deeplink_payload(tenant_id: int, user_id: int) -> str:
    """Генерировать payload для deeplink с HMAC подписью"""
    nonce = secrets.token_urlsafe(16)
    payload = f"{tenant_id}:{user_id}:{nonce}"
    
    # Подписываем HMAC
    signature = hmac.new(
        settings.SECRET_KEY.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()[:16]
    
    return f"{payload}:{signature}"


@router.get("/deeplink", response_model=DeeplinkResponse)
async def get_telegram_deeplink(
    user_id: int = Query(..., description="User ID for deeplink"),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Получить deeplink для подписки на Telegram бота"""
    
    # Определяем какой бот использовать
    settings_record = db.query(TenantSettings).filter(
        TenantSettings.tenant_id == current_user.tenant_id
    ).first()
    
    if settings_record and settings_record.tg_sender == "brand":
        # Проверяем активного бренд-бота
        bot = db.query(TelegramBot).filter(
            and_(
                TelegramBot.tenant_id == current_user.tenant_id,
                TelegramBot.status == "active"
            )
        ).first()
        
        if bot:
            username = bot.username
        else:
            # Fallback на системный бот
            username = settings.SYSTEM_TG_BOT_USERNAME.replace("@", "")
    else:
        # Системный бот
        username = settings.SYSTEM_TG_BOT_USERNAME.replace("@", "")
    
    # Генерируем payload
    payload = _generate_deeplink_payload(current_user.tenant_id, user_id)
    
    # Создаем deeplink
    deeplink = f"https://t.me/{username}?start={payload}"
    
    # QR данные (можно использовать для генерации QR кода)
    qr_data = deeplink
    
    return DeeplinkResponse(
        deeplink=deeplink,
        qr_data=qr_data,
        username=f"@{username}"
    )


@router.get("/test-client")
def get_test_telegram_client(
    current_user: User = Depends(get_current_user)
):
    """Получить тестового Telegram клиента из env (только для админов)"""
    # Проверяем, является ли пользователь админом
    if current_user.role != "admin":
        raise HTTPException(
            status_code=403,
            detail="Доступ разрешен только администраторам"
        )
    
    # Получаем тестовый chat_id из env
    test_chat_id = settings.TEST_TELEGRAM_CHAT_ID
    if not test_chat_id:
        return {"chat_id": None, "available": False}
    
    return {
        "chat_id": test_chat_id,
        "available": True,
        "label": f"Тестовый клиент ({test_chat_id})",
        "is_test": True  # Флаг что это тестовый клиент из env
    }


@router.post("/send-test", response_model=SendTestResponse)
async def send_telegram_test(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Отправить тестовое сообщение в Telegram"""
    
    # Проверяем есть ли у пользователя tg_chat_id
    if not current_user.email:
        return SendTestResponse(
            success=False,
            message="User email not found",
            error="User email not found"
        )
    
    # Создаем или находим тестового клиента
    test_customer = db.query(Customer).filter(
        and_(
            Customer.tenant_id == current_user.tenant_id,
            Customer.email == current_user.email
        )
    ).first()
    
    if not test_customer:
        test_customer = Customer(
            tenant_id=current_user.tenant_id,
            email=current_user.email,
            tg_chat_id=None,  # Будет заполнен при подписке
            tags=["test"],
            meta={"name": "Test User", "source": "telegram_test"}
        )
        db.add(test_customer)
        db.commit()
        db.refresh(test_customer)
    
    if not test_customer.tg_chat_id:
        return SendTestResponse(
            success=False,
            message="User not subscribed to Telegram. Please use deeplink to subscribe first.",
            error="User not subscribed to Telegram. Please use deeplink to subscribe first."
        )
    
    # Определяем какой бот использовать
    from app.services.telegram_sender import choose_telegram_sender
    
    bot_token = await choose_telegram_sender(current_user.tenant_id)
    if not bot_token:
        return SendTestResponse(
            success=False,
            message="No Telegram bot configured",
            error="No Telegram bot configured"
        )
    
    # Отправляем тестовое сообщение
    test_message = f"🎉 Тестовое уведомление от {settings.APP_NAME}!\n\nСистема уведомлений работает корректно."
    
    try:
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"https://api.telegram.org/bot{bot_token}/sendMessage",
                json={
                    "chat_id": test_customer.tg_chat_id,
                    "text": test_message,
                    "parse_mode": "Markdown"
                },
                timeout=10.0
            )
            
            if response.status_code == 200:
                result = response.json()
                if result.get("ok"):
                    return SendTestResponse(
                        success=True,
                        message="Test message sent successfully"
                    )
                else:
                    return SendTestResponse(
                        success=False,
                        message=f"Telegram API error: {result.get('description')}",
                        error=f"Telegram API error: {result.get('description')}"
                    )
            else:
                return SendTestResponse(
                    success=False,
                    message=f"HTTP {response.status_code}",
                    error=f"HTTP {response.status_code}"
                )
                
    except Exception as e:
        return SendTestResponse(
            success=False,
            message=f"Failed to send message: {str(e)}",
            error=f"Failed to send message: {str(e)}"
        )


@router.get("/bots")
async def get_telegram_bots(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Получить список всех Telegram ботов (системный + кастомные)"""
    
    # Получаем настройки тенанта
    settings_record = db.query(TenantSettings).filter(
        TenantSettings.tenant_id == current_user.tenant_id
    ).first()
    
    tg_sender = "system"
    if settings_record:
        if settings_record.tg_sender == "brand":
            tg_sender = "brand"
        elif settings_record.tg_sender == "disabled":
            tg_sender = "disabled"
    
    # Системный бот (всегда доступен)
    system_bot = {
        "id": "system",
        "name": "Системный бот",
        "username": settings.SYSTEM_TG_BOT_USERNAME,
        "type": "system",
        "status": "active",
        "is_active": tg_sender == "system",  # Активен только если tg_sender == "system"
        "subscribers_count": db.query(Customer).filter(
            and_(
                Customer.tenant_id == current_user.tenant_id,
                Customer.tg_chat_id.isnot(None),
                Customer.opt_out == False
            )
        ).count()
    }
    
    # Кастомные боты
    custom_bots = []
    brand_bot = db.query(TelegramBot).filter(
        TelegramBot.tenant_id == current_user.tenant_id
    ).first()
    
    if brand_bot:
        custom_bots.append({
            "id": brand_bot.id,
            "name": "Мой бренд-бот",
            "username": f"@{brand_bot.username}" if brand_bot.username else None,
            "type": "brand",
            "status": brand_bot.status,
            "is_active": tg_sender == "brand" and brand_bot.status == "active",
            "created_at": brand_bot.created_at.isoformat() if brand_bot.created_at else None,
            "updated_at": brand_bot.updated_at.isoformat() if brand_bot.updated_at else None,
        })
    
    bots = [system_bot]
    if custom_bots:
        bots.extend(custom_bots)
    
    return {"bots": bots, "current_sender": tg_sender, "is_disabled": tg_sender == "disabled"}


@router.get("/status")
async def get_telegram_status(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Получить статус Telegram интеграции"""
    
    # Получаем настройки тенанта
    settings_record = db.query(TenantSettings).filter(
        TenantSettings.tenant_id == current_user.tenant_id
    ).first()
    
    tg_sender = "system"
    bot_username = settings.SYSTEM_TG_BOT_USERNAME
    webhook_status = "system"
    subscribers_count = 0
    
    if settings_record and settings_record.tg_sender == "brand":
        tg_sender = "brand"
        
        # Получаем информацию о бренд-боте
        bot = db.query(TelegramBot).filter(
            TelegramBot.tenant_id == current_user.tenant_id
        ).first()
        
        if bot and bot.status == "active":
            bot_username = f"@{bot.username}"
            webhook_status = "active"
        else:
            webhook_status = "disabled"
    
    # Считаем подписчиков
    subscribers_count = db.query(Customer).filter(
        and_(
            Customer.tenant_id == current_user.tenant_id,
            Customer.tg_chat_id.isnot(None),
            Customer.opt_out == False
        )
    ).count()
    
    return {
        "sender": tg_sender,
        "bot_username": bot_username,
        "webhook_status": webhook_status,
        "subscribers_count": subscribers_count
    }


@router.post("/channels/test", response_model=ChannelTestResponse)
async def test_channel(
    data: ChannelTestRequest,
    current_user: User = Depends(get_current_user)
):
    """Отправить тестовое сообщение в любой канал"""
    
    try:
        if data.channel == "telegram":
            # Используем TelegramAdapter который автоматически выберет Bot API или MTProto
            from app.channels.telegram import TelegramAdapter
            
            adapter = TelegramAdapter()
            
            # Определяем использовать ли MTProto явно (если recipient это username)
            use_mtproto = data.recipient.startswith('@')
            
            result = await adapter.send(
                target=data.recipient,
                content=data.message,
                tenant_id=current_user.tenant_id,
                parse_mode="Markdown",
                use_mtproto=use_mtproto
                )
                
            if result.success:
                method = result.response_meta.get("method", "bot_api") if result.response_meta else "bot_api"
                method_text = "через Telegram Client API (MTProto)" if method.startswith("mtproto") else "через Telegram Bot API"
                return ChannelTestResponse(
                    success=True,
                    message=f"Тестовое сообщение успешно отправлено в Telegram {method_text}"
                )
            else:
                return ChannelTestResponse(
                    success=False,
                    message=result.error or "Ошибка отправки в Telegram",
                    error=result.error or "Unknown error"
                )
        
        elif data.channel == "email":
            from app.channels.email import EmailAdapter
            
            adapter = EmailAdapter()
            result = await adapter.send(
                target=data.recipient,
                content=data.message,
                subject="Тестовое сообщение",
                tenant_id=current_user.tenant_id
            )
            
            if result.success:
                return ChannelTestResponse(
                    success=True,
                    message="Тестовое сообщение успешно отправлено на email"
                )
            else:
                return ChannelTestResponse(
                    success=False,
                    message=f"Ошибка отправки email: {result.error}",
                    error=str(result.error)
                )
        
        elif data.channel == "vk":
            from app.channels.vk import VKAdapter
            
            adapter = VKAdapter()
            result = await adapter.send(
                target=data.recipient,
                content=data.message,
                tenant_id=current_user.tenant_id
            )
            
            if result.success:
                return ChannelTestResponse(
                    success=True,
                    message="Тестовое сообщение успешно отправлено в VK"
                )
            else:
                return ChannelTestResponse(
                    success=False,
                    message=f"Ошибка отправки VK: {result.error}",
                    error=str(result.error)
                )
        
        else:
            return ChannelTestResponse(
                success=False,
                message=f"Неподдерживаемый канал: {data.channel}",
                error=f"Unsupported channel: {data.channel}"
            )
    
    except Exception as e:
        return ChannelTestResponse(
            success=False,
            message=f"Ошибка отправки: {str(e)}",
            error=str(e)
        )
