"""
OAuth авторизация для CRM систем (AmoCRM, Bitrix24)
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import and_
import httpx
from typing import Optional

from app.db.session import get_db
from app.db.models import User, Integration
from app.api.deps import get_current_user
from app.core.config import get_settings
import hmac
import hashlib
import secrets
import base64
from datetime import datetime

router = APIRouter(prefix="/oauth", tags=["oauth"])


def _generate_secure_state(tenant_id: int) -> str:
    """Генерирует безопасный state с HMAC подписью"""
    nonce = secrets.token_urlsafe(32)
    data = f"{tenant_id}:{nonce}"
    signature = hmac.new(
        get_settings().SECRET_KEY.encode(),
        data.encode(),
        hashlib.sha256
    ).hexdigest()
    return base64.urlsafe_b64encode(f"{data}:{signature}".encode()).decode()


def _verify_secure_state(state: str) -> Optional[int]:
    """Проверяет HMAC подпись state и возвращает tenant_id"""
    try:
        decoded = base64.urlsafe_b64decode(state.encode()).decode()
        data, signature = decoded.rsplit(":", 1)
        tenant_id_str, nonce = data.split(":", 1)
        
        expected_signature = hmac.new(
            get_settings().SECRET_KEY.encode(),
            data.encode(),
            hashlib.sha256
        ).hexdigest()
        
        if not hmac.compare_digest(signature, expected_signature):
            return None
            
        return int(tenant_id_str)
    except Exception:
        return None


@router.get("/amocrm/authorize")
def amocrm_authorize(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """
    Получить URL для OAuth авторизации в AmoCRM
    """
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id,
            Integration.type == 'amocrm'
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция AmoCRM не найдена")
    
    config = integration.config
    client_id = config.get('client_id')
    redirect_uri = config.get('redirect_uri')
    
    if not client_id or not redirect_uri:
        raise HTTPException(
            status_code=400,
            detail="Не заполнены client_id или redirect_uri в конфигурации"
        )
    
    # Формируем URL для авторизации
    base_url = config.get('api_url', '').rstrip('/')
    auth_url = (
        f"{base_url}/oauth"
        f"?client_id={client_id}"
        f"&state={integration_id}"
        f"&mode=post_message"
    )
    
    return {
        "authorization_url": auth_url,
        "state": integration_id,
        "redirect_uri": redirect_uri
    }


@router.get("/amocrm/callback")
async def amocrm_callback(
    code: str = Query(..., description="Authorization code from AmoCRM"),
    state: int = Query(..., description="Integration ID"),
    referer: Optional[str] = Query(None),
    platform: Optional[str] = Query(None),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """
    Обработка OAuth callback от AmoCRM
    """
    integration = db.query(Integration).filter(
        and_(
            Integration.id == state,
            Integration.tenant_id == current_user.tenant_id,
            Integration.type == 'amocrm'
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция AmoCRM не найдена")
    
    config = integration.config
    client_id = config.get('client_id')
    client_secret = config.get('client_secret')
    redirect_uri = config.get('redirect_uri')
    base_url = config.get('api_url', '').rstrip('/')
    
    # Обмениваем authorization code на access token
    async with httpx.AsyncClient() as client:
        try:
            response = await client.post(
                f"{base_url}/oauth2/access_token",
                json={
                    "client_id": client_id,
                    "client_secret": client_secret,
                    "grant_type": "authorization_code",
                    "code": code,
                    "redirect_uri": redirect_uri
                }
            )
            
            if response.status_code != 200:
                raise HTTPException(
                    status_code=400,
                    detail=f"Ошибка получения токена: {response.text}"
                )
            
            token_data = response.json()
            
            # Сохраняем токены в конфигурации
            config['access_token'] = token_data.get('access_token')
            config['refresh_token'] = token_data.get('refresh_token')
            config['token_type'] = token_data.get('token_type')
            config['expires_in'] = token_data.get('expires_in')
            
            integration.config = config
            integration.status = 'connected'
            integration.last_error = None
            
            db.commit()
            
            # Возвращаем HTML страницу, которая отправляет сообщение в родительское окно
            html_content = f"""
            <!DOCTYPE html>
            <html>
            <head>
                <title>amoCRM авторизация</title>
                <style>
                    body {{
                        font-family: Arial, sans-serif;
                        text-align: center;
                        padding: 50px;
                        background-color: #f5f5f5;
                    }}
                    .success {{
                        color: #52c41a;
                        font-size: 18px;
                        margin-bottom: 20px;
                    }}
                    .loading {{
                        color: #1890ff;
                        font-size: 16px;
                    }}
                </style>
            </head>
            <body>
                <div class="success">✅ amoCRM успешно подключен!</div>
                <div class="loading">Закрытие окна...</div>
                <script>
                    // Отправляем сообщение в родительское окно
                    if (window.opener) {{
                        window.opener.postMessage({{
                            type: 'amocrm_auth_success',
                            integration_id: {integration.id}
                        }}, window.location.origin);
                    }}
                    
                    // Закрываем окно через 2 секунды
                    setTimeout(() => {{
                        window.close();
                    }}, 2000);
                </script>
            </body>
            </html>
            """
            
            from fastapi.responses import HTMLResponse
            return HTMLResponse(content=html_content)
            
        except Exception as e:
            integration.status = 'error'
            integration.last_error = f"OAuth error: {str(e)}"
            db.commit()
            
            # Возвращаем HTML страницу с ошибкой
            html_content = f"""
            <!DOCTYPE html>
            <html>
            <head>
                <title>amoCRM авторизация - Ошибка</title>
                <style>
                    body {{
                        font-family: Arial, sans-serif;
                        text-align: center;
                        padding: 50px;
                        background-color: #f5f5f5;
                    }}
                    .error {{
                        color: #ff4d4f;
                        font-size: 18px;
                        margin-bottom: 20px;
                    }}
                    .loading {{
                        color: #1890ff;
                        font-size: 16px;
                    }}
                </style>
            </head>
            <body>
                <div class="error">❌ Ошибка авторизации amoCRM</div>
                <div style="color: #666; margin-bottom: 20px;">{str(e)}</div>
                <div class="loading">Закрытие окна...</div>
                <script>
                    // Отправляем сообщение об ошибке в родительское окно
                    if (window.opener) {{
                        window.opener.postMessage({{
                            type: 'amocrm_auth_error',
                            error: '{str(e)}'
                        }}, window.location.origin);
                    }}
                    
                    // Закрываем окно через 3 секунды
                    setTimeout(() => {{
                        window.close();
                    }}, 3000);
                </script>
            </body>
            </html>
            """
            
            from fastapi.responses import HTMLResponse
            return HTMLResponse(content=html_content)


@router.post("/amocrm/refresh")
async def amocrm_refresh_token(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """
    Обновить access token для AmoCRM
    """
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id,
            Integration.type == 'amocrm'
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция AmoCRM не найдена")
    
    config = integration.config
    refresh_token = config.get('refresh_token')
    
    if not refresh_token:
        raise HTTPException(status_code=400, detail="Refresh token не найден")
    
    client_id = config.get('client_id')
    client_secret = config.get('client_secret')
    redirect_uri = config.get('redirect_uri')
    base_url = config.get('api_url', '').rstrip('/')
    
    async with httpx.AsyncClient() as client:
        try:
            response = await client.post(
                f"{base_url}/oauth2/access_token",
                json={
                    "client_id": client_id,
                    "client_secret": client_secret,
                    "grant_type": "refresh_token",
                    "refresh_token": refresh_token,
                    "redirect_uri": redirect_uri
                }
            )
            
            if response.status_code != 200:
                raise HTTPException(
                    status_code=400,
                    detail=f"Ошибка обновления токена: {response.text}"
                )
            
            token_data = response.json()
            
            # Обновляем токены
            config['access_token'] = token_data.get('access_token')
            config['refresh_token'] = token_data.get('refresh_token')
            config['expires_in'] = token_data.get('expires_in')
            
            integration.config = config
            integration.status = 'connected'
            integration.last_error = None
            
            db.commit()
            
            return {
                "success": True,
                "message": "Токен успешно обновлен"
            }
            
        except Exception as e:
            integration.status = 'error'
            integration.last_error = f"Token refresh error: {str(e)}"
            db.commit()
            
            raise HTTPException(status_code=400, detail=str(e))


@router.get("/bitrix24/authorize")
def bitrix24_authorize(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """
    Получить URL для OAuth авторизации в Bitrix24 через единое приложение
    """
    settings = get_settings()
    
    if not settings.BITRIX_CLIENT_ID:
        raise HTTPException(
            status_code=500,
            detail="BITRIX_CLIENT_ID не настроен на сервере"
        )
    
    # Генерируем безопасный state
    state = _generate_secure_state(current_user.tenant_id)
    
    # Формируем URL для авторизации через единое приложение
    auth_url = (
        f"https://oauth.bitrix.info/oauth/authorize"
        f"?client_id={settings.BITRIX_CLIENT_ID}"
        f"&response_type=code"
        f"&redirect_uri={settings.BITRIX_REDIRECT_URI}"
        f"&state={state}"
    )
    
    return {
        "authorization_url": auth_url,
        "state": state
    }


@router.get("/bitrix24/callback")
async def bitrix24_callback(
    code: str = Query(..., description="Authorization code from Bitrix24"),
    state: str = Query(..., description="Secure state parameter"),
    domain: Optional[str] = Query(None),
    member_id: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    """
    Обработка OAuth callback от Bitrix24 через единое приложение
    """
    settings = get_settings()
    
    if not settings.BITRIX_CLIENT_ID or not settings.BITRIX_CLIENT_SECRET:
        raise HTTPException(
            status_code=500,
            detail="BITRIX_CLIENT_ID или BITRIX_CLIENT_SECRET не настроены на сервере"
        )
    
    # Проверяем безопасный state
    tenant_id = _verify_secure_state(state)
    if not tenant_id:
        raise HTTPException(status_code=400, detail="Неверный state параметр")
    
    # Получаем пользователя по tenant_id
    user = db.query(User).filter(User.tenant_id == tenant_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="Пользователь не найден")
    
    # Обмениваем code на access token используя серверные credentials
    async with httpx.AsyncClient() as client:
        try:
            response = await client.post(
                "https://oauth.bitrix.info/oauth/token",
                data={
                    "grant_type": "authorization_code",
                    "client_id": settings.BITRIX_CLIENT_ID,
                    "client_secret": settings.BITRIX_CLIENT_SECRET,
                    "code": code,
                    "redirect_uri": settings.BITRIX_REDIRECT_URI
                }
            )
            
            if response.status_code != 200:
                raise HTTPException(
                    status_code=400,
                    detail=f"Ошибка получения токена: {response.text}"
                )
            
            token_data = response.json()
            
            # Создаем или обновляем интеграцию
            integration = db.query(Integration).filter(
                and_(
                    Integration.tenant_id == tenant_id,
                    Integration.type == 'bitrix24'
                )
            ).first()
            
            if not integration:
                integration = Integration(
                    tenant_id=tenant_id,
                    type='bitrix24',
                    name='Bitrix24 Marketplace App',
                    config={},
                    status='pending'
                )
                db.add(integration)
            
            # Сохраняем токены
            integration.config.update({
                'access_token': token_data.get('access_token'),
                'refresh_token': token_data.get('refresh_token'),
                'expires_in': token_data.get('expires_in'),
                'member_id': member_id,
                'domain': domain,
                'connected_at': datetime.utcnow().isoformat()
            })
            
            integration.status = 'connected'
            integration.last_error = None
            
            db.commit()
            
            # Автоматически регистрируем webhooks
            await _register_bitrix24_webhooks(integration, token_data.get('access_token'), domain)
            
            return {
                "success": True,
                "message": "Bitrix24 успешно подключен",
                "integration_id": integration.id,
                "domain": domain
            }
            
        except Exception as e:
            if integration:
                integration.status = 'error'
                integration.last_error = f"OAuth error: {str(e)}"
                db.commit()
            
            raise HTTPException(status_code=400, detail=str(e))


async def _register_bitrix24_webhooks(integration: Integration, access_token: str, domain: str):
    """Автоматически регистрирует webhooks в Bitrix24"""
    if not domain:
        return
    
    webhook_url = f"https://your-domain.com/api/v1/integrations/bitrix24/webhook"
    events = [
        "onCrmDealAdd",
        "onCrmDealUpdate", 
        "onCrmContactAdd",
        "onCrmContactUpdate"
    ]
    
    async with httpx.AsyncClient() as client:
        for event in events:
            try:
                response = await client.post(
                    f"https://{domain}/rest/event.bind.json",
                    params={
                        "auth": access_token,
                        "event": event,
                        "handler": webhook_url
                    }
                )
                
                if response.status_code == 200:
                    print(f"Webhook {event} зарегистрирован для {domain}")
                else:
                    print(f"Ошибка регистрации webhook {event}: {response.text}")
                    
            except Exception as e:
                print(f"Ошибка при регистрации webhook {event}: {e}")

