"""
Bitrix24 BYO-Keys API endpoints
Реализует подключение Bitrix24 в режиме Bring Your Own Keys
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import and_
import httpx
from typing import Optional
from datetime import datetime, timedelta
from pydantic import BaseModel, HttpUrl

from app.db.session import get_db
from app.db.models import User, CRMConnection, Integration
from app.api.deps import get_current_user
from app.core.config import get_settings

router = APIRouter(prefix="/bitrix", tags=["bitrix-byo"])


class BitrixConnectRequest(BaseModel):
    portal_url: HttpUrl
    client_id: str
    client_secret: str


class BitrixConnectResponse(BaseModel):
    redirect_url: str
    connection_id: int


class BitrixStatusResponse(BaseModel):
    connection_id: int
    status: str
    domain: Optional[str] = None
    portal_url: Optional[str] = None
    connected_at: Optional[datetime] = None
    error_message: Optional[str] = None


class BitrixUpdateRequest(BaseModel):
    portal_url: Optional[HttpUrl] = None
    client_id: Optional[str] = None
    client_secret: Optional[str] = None


class BitrixUpdateResponse(BaseModel):
    connection_id: int
    status: str
    message: str


@router.post("/connect", response_model=BitrixConnectResponse)
def bitrix_connect(
    request: BitrixConnectRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """
    Создает подключение Bitrix24 в режиме BYO-Keys
    """
    settings = get_settings()
    
    # Проверяем, нет ли уже активного подключения
    existing_connection = db.query(CRMConnection).filter(
        and_(
            CRMConnection.tenant_id == current_user.tenant_id,
            CRMConnection.status == 'connected'
        )
    ).first()
    
    if existing_connection:
        raise HTTPException(
            status_code=400,
            detail="У вас уже есть активное подключение к Bitrix24. Сначала удалите его."
        )
    
    # Создаем новое подключение
    connection = CRMConnection(
        tenant_id=current_user.tenant_id,
        portal_url=str(request.portal_url),
        client_id=request.client_id,
        client_secret=request.client_secret,
        status='pending'
    )
    
    db.add(connection)
    db.commit()
    db.refresh(connection)
    
    # Формируем redirect URL для OAuth
    redirect_uri = f"{settings.APP_DOMAIN}/api/bitrix/oauth/callback"
    
    oauth_url = (
        f"https://oauth.bitrix.info/oauth/authorize"
        f"?client_id={request.client_id}"
        f"&response_type=code"
        f"&redirect_uri={redirect_uri}"
        f"&state={connection.id}"
    )
    
    return BitrixConnectResponse(
        redirect_url=oauth_url,
        connection_id=connection.id
    )


@router.get("/get-integration/{connection_id}")
def get_integration_by_connection(
    connection_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Получить integration_id по connection_id"""
    connection = db.query(CRMConnection).filter(
        and_(
            CRMConnection.id == connection_id,
            CRMConnection.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not connection:
        raise HTTPException(status_code=404, detail="Подключение не найдено")
    
    # Ищем Integration по connection_id
    integration = db.query(Integration).filter(
        and_(
            Integration.tenant_id == current_user.tenant_id,
            Integration.type == 'bitrix24',
            Integration.config.op('->>')('connection_id') == str(connection_id)
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    return {
        "integration_id": integration.id,
        "connection_id": connection_id,
        "status": integration.status
    }


@router.get("/oauth/callback")
async def bitrix_oauth_callback(
    code: str = Query(..., description="Authorization code from Bitrix24"),
    state: int = Query(..., description="Connection ID"),
    domain: Optional[str] = Query(None),
    member_id: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    """
    Обработка OAuth callback от Bitrix24
    """
    # Находим подключение
    connection = db.query(CRMConnection).filter(
        CRMConnection.id == state
    ).first()
    
    if not connection:
        raise HTTPException(status_code=404, detail="Подключение не найдено")
    
    # Обмениваем code на access token
    async with httpx.AsyncClient() as client:
        try:
            settings = get_settings()
            redirect_uri = f"{settings.APP_DOMAIN}/api/bitrix/oauth/callback"
            
            response = await client.post(
                "https://oauth.bitrix.info/oauth/token",
                data={
                    "grant_type": "authorization_code",
                    "client_id": connection.client_id,
                    "client_secret": connection.client_secret,
                    "code": code,
                    "redirect_uri": redirect_uri
                }
            )
            
            if response.status_code != 200:
                error_detail = f"Ошибка получения токена: {response.text}"
                connection.status = 'error'
                connection.updated_at = datetime.utcnow()
                db.commit()
                
                raise HTTPException(status_code=400, detail=error_detail)
            
            token_data = response.json()
            
            # Сохраняем токены
            connection.access_token = token_data.get('access_token')
            connection.refresh_token = token_data.get('refresh_token')
            connection.domain = domain
            connection.member_id = member_id
            connection.status = 'connected'
            
            # Вычисляем время истечения токена
            expires_in = token_data.get('expires_in', 3600)
            connection.expires_at = datetime.utcnow() + timedelta(seconds=expires_in)
            
            connection.updated_at = datetime.utcnow()
            db.commit()
            
            # Создаем или обновляем Integration для маппинга полей
            existing_integration = db.query(Integration).filter(
                and_(
                    Integration.tenant_id == connection.tenant_id,
                    Integration.type == 'bitrix24',
                    Integration.config.op('->>')('connection_id') == str(connection.id)
                )
            ).first()
            
            if existing_integration:
                # Обновляем существующую интеграцию
                existing_integration.config = {
                    **existing_integration.config,
                    'access_token': connection.access_token,
                    'domain': connection.domain,
                    'connection_id': connection.id,
                    'portal_url': connection.portal_url
                }
                existing_integration.status = 'connected'
                integration_id = existing_integration.id
            else:
                # Создаем новую интеграцию
                new_integration = Integration(
                    tenant_id=connection.tenant_id,
                    type='bitrix24',
                    name=f'Bitrix24 - {connection.portal_url}',
                    config={
                        'access_token': connection.access_token,
                        'refresh_token': connection.refresh_token,
                        'domain': connection.domain,
                        'connection_id': connection.id,
                        'portal_url': connection.portal_url,
                        'client_id': connection.client_id
                    },
                    status='connected'
                )
                db.add(new_integration)
                integration_id = new_integration.id
            
            db.commit()
            
            return {
                "success": True,
                "message": "Bitrix24 успешно подключен",
                "connection_id": connection.id,
                "integration_id": integration_id,
                "domain": domain
            }
            
        except Exception as e:
            connection.status = 'error'
            connection.updated_at = datetime.utcnow()
            db.commit()
            
            raise HTTPException(status_code=400, detail=f"OAuth error: {str(e)}")


@router.post("/refresh/{connection_id}")
async def bitrix_refresh_token(
    connection_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """
    Обновить access token для Bitrix24
    """
    connection = db.query(CRMConnection).filter(
        and_(
            CRMConnection.id == connection_id,
            CRMConnection.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not connection:
        raise HTTPException(status_code=404, detail="Подключение не найдено")
    
    if not connection.refresh_token:
        raise HTTPException(status_code=400, detail="Refresh token не найден")
    
    async with httpx.AsyncClient() as client:
        try:
            settings = get_settings()
            redirect_uri = f"{settings.APP_DOMAIN}/api/bitrix/oauth/callback"
            
            response = await client.post(
                "https://oauth.bitrix.info/oauth/token",
                data={
                    "grant_type": "refresh_token",
                    "client_id": connection.client_id,
                    "client_secret": connection.client_secret,
                    "refresh_token": connection.refresh_token,
                    "redirect_uri": redirect_uri
                }
            )
            
            if response.status_code != 200:
                error_detail = f"Ошибка обновления токена: {response.text}"
                connection.status = 'error'
                connection.updated_at = datetime.utcnow()
                db.commit()
                
                raise HTTPException(status_code=400, detail=error_detail)
            
            token_data = response.json()
            
            # Обновляем токены
            connection.access_token = token_data.get('access_token')
            connection.refresh_token = token_data.get('refresh_token')
            connection.status = 'connected'
            
            # Обновляем время истечения
            expires_in = token_data.get('expires_in', 3600)
            connection.expires_at = datetime.utcnow() + timedelta(seconds=expires_in)
            
            connection.updated_at = datetime.utcnow()
            db.commit()
            
            return {
                "success": True,
                "message": "Токен успешно обновлен"
            }
            
        except Exception as e:
            connection.status = 'error'
            connection.updated_at = datetime.utcnow()
            db.commit()
            
            raise HTTPException(status_code=400, detail=f"Token refresh error: {str(e)}")


@router.get("/status", response_model=BitrixStatusResponse)
def bitrix_status(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """
    Получить статус подключения Bitrix24
    """
    connection = db.query(CRMConnection).filter(
        and_(
            CRMConnection.tenant_id == current_user.tenant_id,
            CRMConnection.status.in_(['connected', 'pending', 'error'])
        )
    ).order_by(CRMConnection.created_at.desc()).first()
    
    if not connection:
        raise HTTPException(status_code=404, detail="Подключение не найдено")
    
    return BitrixStatusResponse(
        connection_id=connection.id,
        status=connection.status,
        domain=connection.domain,
        portal_url=connection.portal_url,
        connected_at=connection.updated_at if connection.status == 'connected' else None,
        error_message=None  # Можно добавить поле для хранения ошибок
    )


@router.delete("/disconnect/{connection_id}")
def bitrix_disconnect(
    connection_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """
    Удалить подключение Bitrix24
    """
    connection = db.query(CRMConnection).filter(
        and_(
            CRMConnection.id == connection_id,
            CRMConnection.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not connection:
        raise HTTPException(status_code=404, detail="Подключение не найдено")
    
    db.delete(connection)
    db.commit()
    
    return {"success": True, "message": "Подключение удалено"}


@router.post("/test/{connection_id}")
async def bitrix_test_connection(
    connection_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """
    Тестировать подключение к Bitrix24
    """
    connection = db.query(CRMConnection).filter(
        and_(
            CRMConnection.id == connection_id,
            CRMConnection.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not connection:
        raise HTTPException(status_code=404, detail="Подключение не найдено")
    
    if not connection.access_token:
        raise HTTPException(status_code=400, detail="Токен доступа не найден")
    
    async with httpx.AsyncClient() as client:
        try:
            # Тестируем подключение через API Bitrix24
            response = await client.get(
                f"{connection.portal_url}/rest/user.current.json",
                params={"auth": connection.access_token}
            )
            
            if response.status_code == 200:
                user_data = response.json()
                return {
                    "success": True,
                    "message": "Подключение работает",
                    "user": user_data.get('result', {})
                }
            else:
                connection.status = 'error'
                connection.updated_at = datetime.utcnow()
                db.commit()
                
                raise HTTPException(
                    status_code=400,
                    detail=f"Ошибка подключения: {response.text}"
                )
                
        except Exception as e:
            connection.status = 'error'
            connection.updated_at = datetime.utcnow()
            db.commit()
            
            raise HTTPException(status_code=400, detail=f"Test error: {str(e)}")


@router.put("/update/{connection_id}", response_model=BitrixUpdateResponse)
async def update_bitrix_connection(
    connection_id: int,
    request: BitrixUpdateRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """
    Обновить настройки подключения Bitrix24
    """
    connection = db.query(CRMConnection).filter(
        and_(
            CRMConnection.id == connection_id,
            CRMConnection.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not connection:
        raise HTTPException(status_code=404, detail="Подключение не найдено")
    
    # Обновляем поля
    if request.portal_url is not None:
        connection.portal_url = str(request.portal_url)
    if request.client_id is not None:
        connection.client_id = request.client_id
    if request.client_secret is not None:
        connection.client_secret = request.client_secret
    
    # Сбрасываем токены при изменении настроек
    connection.access_token = None
    connection.refresh_token = None
    connection.expires_at = None
    connection.status = 'pending'
    connection.updated_at = datetime.utcnow()
    
    db.commit()
    db.refresh(connection)
    
    return BitrixUpdateResponse(
        connection_id=connection.id,
        status=connection.status,
        message="Настройки обновлены. Требуется повторное подключение."
    )

