import json
import hmac
import hashlib
from datetime import datetime
from fastapi import APIRouter, Request, HTTPException, Query, Path, Depends
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 Customer, TelegramBot, TenantSettings
from app.core.config import get_settings
from app.services.telegram_sender import choose_telegram_sender


router = APIRouter()
settings = get_settings()


class TelegramUpdate(BaseModel):
    update_id: int
    message: dict | None = None


def _verify_webhook_secret(secret: str, tenant_id: int, db: Session) -> bool:
    """Проверить секрет webhook"""
    # Для системного бота используем SECRET_KEY
    if secret == settings.SECRET_KEY:
        return True
    
    # Для бренд-ботов проверяем в БД
    bot = db.query(TelegramBot).filter(
        and_(
            TelegramBot.tenant_id == tenant_id,
            TelegramBot.status == "active"
        )
    ).first()
    
    if bot and bot.webhook_secret:
        return hmac.compare_digest(secret, bot.webhook_secret)
    
    return False


def _parse_deeplink_payload(payload: str) -> tuple[int, int] | None:
    """Парсить payload deeplink и проверить подпись"""
    try:
        parts = payload.split(":")
        if len(parts) != 4:
            return None
        
        tenant_id_str, user_id_str, nonce, signature = parts
        tenant_id = int(tenant_id_str)
        user_id = int(user_id_str)
        
        # Проверяем подпись
        expected_payload = f"{tenant_id}:{user_id}:{nonce}"
        expected_signature = hmac.new(
            settings.SECRET_KEY.encode(),
            expected_payload.encode(),
            hashlib.sha256
        ).hexdigest()[:16]
        
        if not hmac.compare_digest(signature, expected_signature):
            return None
        
        return tenant_id, user_id
        
    except (ValueError, IndexError):
        return None


async def _handle_start_command(tenant_id: int, chat_id: str, user_info: dict, db: Session, payload: str = None):
    """Обработать команду /start"""
    
    # Парсим payload если есть
    user_id = None
    if payload:
        parsed = _parse_deeplink_payload(payload)
        if parsed:
            payload_tenant_id, user_id = parsed
            # Проверяем что tenant_id совпадает
            if payload_tenant_id != tenant_id:
                return {"error": "Invalid payload tenant"}
    
    # Создаем или обновляем клиента
    customer = db.query(Customer).filter(
        and_(
            Customer.tenant_id == tenant_id,
            Customer.tg_chat_id == chat_id
        )
    ).first()
    
    if not customer:
        # Создаем нового клиента
        customer = Customer(
            tenant_id=tenant_id,
            tg_chat_id=chat_id,
            tags=["telegram_subscriber"],
            meta={
                "telegram_username": user_info.get("username"),
                "telegram_first_name": user_info.get("first_name"),
                "telegram_last_name": user_info.get("last_name"),
                "consent_at": datetime.utcnow().isoformat(),
                "source": "telegram_start"
            }
        )
        db.add(customer)
    else:
        # Обновляем существующего клиента
        if not customer.opt_out:  # Не обновляем если пользователь отписался
            customer.meta = {
                **customer.meta,
                "telegram_username": user_info.get("username"),
                "telegram_first_name": user_info.get("first_name"),
                "telegram_last_name": user_info.get("last_name"),
                "consent_at": datetime.utcnow().isoformat(),
                "last_seen": datetime.utcnow().isoformat()
            }
    
    customer.opt_out = False  # Сбрасываем opt_out при /start
    db.commit()
    
    return {"success": True, "customer_id": customer.id}


async def _handle_stop_command(tenant_id: int, chat_id: str, db: Session):
    """Обработать команду /stop или 'стоп'"""
    customer = db.query(Customer).filter(
        and_(
            Customer.tenant_id == tenant_id,
            Customer.tg_chat_id == chat_id
        )
    ).first()
    
    if customer:
        customer.opt_out = True
        customer.meta = {
            **customer.meta,
            "opt_out_at": datetime.utcnow().isoformat()
        }
        db.commit()
    
    return {"success": True}


@router.post("/system/webhook")
async def system_telegram_webhook(
    request: Request,
    secret: str = Query(..., description="Webhook secret"),
    db: Session = Depends(get_db)
):
    """Webhook для системного бота"""
    
    # Проверяем секрет
    if not hmac.compare_digest(secret, settings.SECRET_KEY):
        raise HTTPException(status_code=403, detail="Invalid webhook secret")
    
    # Парсим данные
    try:
        body = await request.body()
        update_data = json.loads(body)
        update = TelegramUpdate(**update_data)
    except Exception as e:
        raise HTTPException(status_code=400, detail=f"Invalid webhook data: {str(e)}")
    
    # Обрабатываем сообщение
    if update.message:
        message = update.message
        chat = message.get("chat", {})
        from_user = message.get("from", {})
        text = message.get("text", "")
        
        chat_id = str(chat.get("id"))
        user_info = {
            "username": from_user.get("username"),
            "first_name": from_user.get("first_name"),
            "last_name": from_user.get("last_name"),
            "id": from_user.get("id")
        }
        
        # Определяем tenant_id из payload команды /start
        tenant_id = None
        if text.startswith("/start "):
            payload = text[7:].strip()  # Убираем "/start "
            parsed = _parse_deeplink_payload(payload)
            if parsed:
                tenant_id, _ = parsed
        
        if tenant_id and text.startswith("/start"):
            result = await _handle_start_command(tenant_id, chat_id, user_info, db, text[7:].strip())
        elif text.lower() in ["/stop", "стоп", "stop"]:
            # Для /stop нужен tenant_id, попробуем найти по клиенту
            customer = db.query(Customer).filter(
                Customer.tg_chat_id == chat_id
            ).first()
            if customer:
                result = await _handle_stop_command(customer.tenant_id, chat_id, db)
            else:
                result = {"error": "Customer not found"}
        else:
            result = {"message": "Unknown command"}
        
        return {"ok": True, "result": result}
    
    return {"ok": True}


@router.post("/webhook/{tenant_id}")
async def brand_telegram_webhook(
    request: Request,
    tenant_id: int = Path(..., description="Tenant ID"),
    secret: str = Query(..., description="Webhook secret"),
    db: Session = Depends(get_db)
):
    """Webhook для бренд-бота"""
    
    # Проверяем секрет
    if not _verify_webhook_secret(secret, tenant_id, db):
        raise HTTPException(status_code=403, detail="Invalid webhook secret")
    
    # Парсим данные
    try:
        body = await request.body()
        update_data = json.loads(body)
        update = TelegramUpdate(**update_data)
    except Exception as e:
        raise HTTPException(status_code=400, detail=f"Invalid webhook data: {str(e)}")
    
    # Обрабатываем сообщение
    if update.message:
        message = update.message
        chat = message.get("chat", {})
        from_user = message.get("from", {})
        text = message.get("text", "")
        
        chat_id = str(chat.get("id"))
        user_info = {
            "username": from_user.get("username"),
            "first_name": from_user.get("first_name"),
            "last_name": from_user.get("last_name"),
            "id": from_user.get("id")
        }
        
        if text.startswith("/start"):
            payload = text[7:].strip() if len(text) > 7 else None
            result = await _handle_start_command(tenant_id, chat_id, user_info, db, payload)
        elif text.lower() in ["/stop", "стоп", "stop"]:
            result = await _handle_stop_command(tenant_id, chat_id, db)
        else:
            result = {"message": "Unknown command"}
        
        return {"ok": True, "result": result}
    
    return {"ok": True}


@router.post("/test-webhook")
async def test_webhook(
    request: Request,
    db: Session = Depends(get_db)
):
    """Тестовый webhook для проверки работы"""
    try:
        body = await request.body()
        data = json.loads(body)
        return {"ok": True, "received": data}
    except Exception as e:
        return {"ok": False, "error": str(e)}
