from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks, Query, Request
from sqlalchemy.orm import Session
from sqlalchemy import and_
from typing import List, Optional, Dict, Any
from datetime import datetime
from pydantic import BaseModel, ConfigDict
import httpx
import base64

from app.db.session import get_db
from app.db.models import User, Integration, IntegrationSyncLog, CRMFieldMapping
from app.api.deps import get_current_user
from app.core.config import get_settings
from app.utils.encryption import encrypt_token, decrypt_token


def _validate_integration_status(integration: Integration) -> str:
    """
    Валидирует статус интеграции на основе её конфигурации
    
    Args:
        integration: объект интеграции
        
    Returns:
        str: корректный статус интеграции
    """
    config = integration.config or {}
    
    # API интеграция всегда в статусе connected (не требует авторизации)
    if integration.type == "api":
        return "connected"
    
    # Проверяем обязательные поля для Bitrix24
    if integration.type == "bitrix24":
        required_fields = ["client_id", "client_secret", "api_url"]
        for field in required_fields:
            if not config.get(field):
                return "incomplete"  # Неполная конфигурация
    
    # Проверяем обязательные поля для amoCRM  
    elif integration.type == "amocrm":
        required_fields = ["client_id", "client_secret", "api_url"]
        for field in required_fields:
            if not config.get(field):
                return "incomplete"
    
    # Если все поля есть, но нет access_token - ожидание авторизации
    if not config.get("access_token"):
        return "pending"
    
    # Если есть токен, но была ошибка - проверяем время последней ошибки
    if integration.last_error and integration.error_timestamp:
        # Если ошибка была недавно (менее 5 минут назад) - считаем что есть проблема
        from datetime import timedelta
        if datetime.utcnow() - integration.error_timestamp < timedelta(minutes=5):
            return "error"
    
    # Если все проверки пройдены - connected
    return "connected"

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


# Pydantic schemas
class IntegrationConfig(BaseModel):
    """Конфигурация для разных типов CRM"""
    api_url: Optional[str] = None
    client_id: Optional[str] = None
    client_secret: Optional[str] = None
    access_token: Optional[str] = None
    refresh_token: Optional[str] = None
    api_key: Optional[str] = None
    username: Optional[str] = None
    password: Optional[str] = None
    redirect_uri: Optional[str] = None
    custom_fields: Optional[Dict[str, Any]] = None
    channels: Optional[List[str]] = None  # Каналы отправки: ['email', 'telegram', 'vk']
    
    model_config = ConfigDict(extra="allow")  # Разрешаем дополнительные поля


class IntegrationCreate(BaseModel):
    type: str  # amocrm, bitrix24, 1c, custom, api
    name: str
    config: IntegrationConfig


class IntegrationUpdate(BaseModel):
    name: Optional[str] = None
    config: Optional[IntegrationConfig] = None
    is_active: Optional[bool] = None


class IntegrationOut(BaseModel):
    id: int
    tenant_id: int
    type: str
    name: str
    status: str
    last_sync_at: Optional[datetime]
    last_error: Optional[str]
    error_type: Optional[str]  # Тип ошибки для лучшего UX
    error_timestamp: Optional[datetime]  # Время последней ошибки
    sync_stats: Dict[str, Any]
    config: Dict[str, Any]  # Конфигурация интеграции
    is_active: bool
    created_at: datetime
    updated_at: datetime

    class Config:
        from_attributes = True


class SyncLogOut(BaseModel):
    id: int
    integration_id: int
    sync_type: str
    status: str
    records_processed: int
    records_created: int
    records_updated: int
    records_failed: int
    error_message: Optional[str]
    started_at: datetime
    completed_at: Optional[datetime]
    sync_metadata: Dict[str, Any]

    class Config:
        from_attributes = True


# API Endpoints
@router.get("", response_model=List[IntegrationOut])
def list_integrations(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
    type: Optional[str] = None,
    is_active: Optional[bool] = None,
):
    """Получить список всех интеграций"""
    query = db.query(Integration).filter(Integration.tenant_id == current_user.tenant_id)
    
    if type:
        query = query.filter(Integration.type == type)
    if is_active is not None:
        query = query.filter(Integration.is_active == is_active)
    
    integrations = query.order_by(Integration.created_at.desc()).all()
    
    # Валидируем статус каждой интеграции
    for integration in integrations:
        validated_status = _validate_integration_status(integration)
        if integration.status != validated_status:
            integration.status = validated_status
            db.commit()
            db.refresh(integration)
    
    return integrations


@router.post("", response_model=IntegrationOut, status_code=201)
def create_integration(
    data: IntegrationCreate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Создать новую интеграцию"""
    # Валидация типа
    valid_types = ['amocrm', 'bitrix24', '1c', 'custom', 'api']
    if data.type not in valid_types:
        raise HTTPException(
            status_code=400, 
            detail=f"Неверный тип интеграции. Допустимые значения: {', '.join(valid_types)}"
        )
    
    # Проверка на дубликаты - для типов api, custom, 1c удаляем все существующие интеграции этого типа
    if data.type in ['api', 'custom', '1c']:
        existing_integrations = db.query(Integration).filter(
            and_(
                Integration.tenant_id == current_user.tenant_id,
                Integration.type == data.type
            )
        ).all()
        
        if existing_integrations:
            print(f"Найдено {len(existing_integrations)} существующих интеграций типа {data.type}, удаляем их")
            try:
                for existing_integration in existing_integrations:
                    # Удаляем связанные записи
                    db.query(CRMFieldMapping).filter(
                        CRMFieldMapping.integration_id == existing_integration.id
                    ).delete()
                    
                    db.query(IntegrationSyncLog).filter(
                        IntegrationSyncLog.integration_id == existing_integration.id
                    ).delete()
                    
                    # Удаляем саму интеграцию
                    db.delete(existing_integration)
                
                db.commit()
                print(f"Удалено {len(existing_integrations)} дублирующих интеграций типа {data.type}")
            except Exception as e:
                db.rollback()
                print(f"Ошибка при удалении дублирующих интеграций: {e}")
                raise HTTPException(
                    status_code=500,
                    detail=f"Ошибка при удалении дублирующих интеграций: {str(e)}"
                )
    else:
        # Для других типов используем существующую логику проверки дубликатов
        existing_integration = _check_for_duplicates(db, current_user.tenant_id, data.type, data.config)
        if existing_integration:
            print(f"Найдена дублирующая интеграция {data.type}, удаляем старую и создаем новую")
            try:
                # Удаляем связанные записи
                db.query(CRMFieldMapping).filter(
                    CRMFieldMapping.integration_id == existing_integration.id
                ).delete()
                
                db.query(IntegrationSyncLog).filter(
                    IntegrationSyncLog.integration_id == existing_integration.id
                ).delete()
                
                # Удаляем саму интеграцию
                db.delete(existing_integration)
                db.commit()
                
                print(f"Дублирующая интеграция {existing_integration.id} удалена")
            except Exception as e:
                db.rollback()
                print(f"Ошибка при удалении дублирующей интеграции: {e}")
                raise HTTPException(
                    status_code=500,
                    detail=f"Ошибка при удалении дублирующей интеграции: {str(e)}"
                )
    
    # Автоматическое генерирование уникального имени если не указано
    if not data.name or data.name.strip() == "":
        data.name = _generate_unique_name(db, current_user.tenant_id, data.type, data.config)
    
    # Создание интеграции
    # Для API интеграции сразу устанавливаем статус connected (не требует авторизации)
    initial_status = 'connected' if data.type == 'api' else 'pending'
    
    integration = Integration(
        tenant_id=current_user.tenant_id,
        type=data.type,
        name=data.name,
        config=data.config.model_dump(exclude_none=True),
        status=initial_status,
        sync_stats={}
    )
    
    db.add(integration)
    db.commit()
    db.refresh(integration)
    
    return integration


@router.get("/{integration_id}", response_model=IntegrationOut)
def get_integration(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Получить интеграцию по ID"""
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    return integration


@router.put("/{integration_id}", response_model=IntegrationOut)
def update_integration(
    integration_id: int,
    data: IntegrationUpdate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Обновить интеграцию"""
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    # Обновление полей
    if data.name is not None:
        integration.name = data.name
    if data.config is not None:
        # Объединяем существующую конфигурацию с новой
        current_config = integration.config or {}
        new_config = data.config.model_dump(exclude_none=True)
        integration.config = {**current_config, **new_config}
    if data.is_active is not None:
        integration.is_active = data.is_active
    
    integration.updated_at = datetime.utcnow()
    
    db.commit()
    db.refresh(integration)
    
    return integration


@router.delete("/{integration_id}")
def delete_integration(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Удалить интеграцию"""
    print(f"Попытка удаления интеграции {integration_id} для пользователя {current_user.id}")
    
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        print(f"Интеграция {integration_id} не найдена")
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    print(f"Найдена интеграция: {integration.name} (тип: {integration.type})")
    
    try:
        # Сначала удаляем связанные записи
        from app.db.models import IntegrationSyncLog, CRMFieldMapping
        
        # Удаляем журнал синхронизации (с проверкой tenant_id для безопасности)
        sync_logs = db.query(IntegrationSyncLog).filter(
            and_(
                IntegrationSyncLog.integration_id == integration_id,
                IntegrationSyncLog.tenant_id == current_user.tenant_id
            )
        ).all()
        for log in sync_logs:
            db.delete(log)
        
        # Удаляем сопоставления полей (с проверкой tenant_id для безопасности)
        field_mappings = db.query(CRMFieldMapping).filter(
            and_(
                CRMFieldMapping.integration_id == integration_id,
                CRMFieldMapping.tenant_id == current_user.tenant_id
            )
        ).all()
        for mapping in field_mappings:
            db.delete(mapping)
        
        # Теперь удаляем саму интеграцию
        db.delete(integration)
        db.commit()
        print(f"Интеграция {integration_id} и связанные записи успешно удалены")
        return {"message": "Интеграция успешно удалена"}
    except Exception as e:
        print(f"Ошибка при удалении интеграции {integration_id}: {str(e)}")
        db.rollback()
        raise HTTPException(status_code=500, detail=f"Ошибка удаления интеграции: {str(e)}")


@router.post("/{integration_id}/test")
def test_integration(
    integration_id: int,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Тестировать подключение к CRM"""
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    # Запускаем тестирование в фоне через Celery
    from app.workers.crm_sync import test_crm_connection
    
    task = test_crm_connection.delay(integration_id)
    
    return {
        "success": True,
        "message": "Тестирование подключения запущено",
        "task_id": task.id,
        "status": "testing"
    }


@router.post("/{integration_id}/sync")
def sync_integration(
    integration_id: int,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
    sync_type: str = "customers",
):
    """Запустить синхронизацию с CRM"""
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    # API интеграция не требует синхронизации
    if integration.type == 'api':
        raise HTTPException(status_code=400, detail="API интеграция не требует синхронизации. Используйте API endpoints для отправки уведомлений.")
    
    if not integration.is_active:
        raise HTTPException(status_code=400, detail="Интеграция неактивна")
    
    if integration.status == 'pending_auth':
        raise HTTPException(status_code=400, detail="Интеграция ожидает авторизации. Сначала завершите процесс авторизации.")
    
    # Создаем лог синхронизации
    sync_log = IntegrationSyncLog(
        integration_id=integration.id,
        sync_type=sync_type,
        status='in_progress',
        started_at=datetime.utcnow()
    )
    db.add(sync_log)
    db.commit()
    db.refresh(sync_log)
    
    # Реальная синхронизация с CRM
    try:
        # Получаем конфигурацию интеграции
        config = integration.config or {}
        api_url = config.get('api_url', '').rstrip('/')
        access_token = config.get('access_token')
        
        print(f"Начинаем синхронизацию для интеграции {integration_id}")
        print(f"API URL: {api_url}")
        print(f"Access token: {access_token[:20]}..." if access_token else "None")
        
        import httpx
        import asyncio
        
        if not api_url or not access_token:
            raise Exception("Не настроены api_url или access_token")
        
        # Временно отключаем проверку демо-токена для тестирования
        # if access_token.startswith("demo_token_"):
        #     raise Exception("Используется демо-токен. Настройте реальные credentials для amoCRM")
        
        # Синхронизируем данные в зависимости от типа CRM
        if integration.type == "amocrm":
            # Синхронизация с amoCRM (синхронная версия)
            import requests
            
            # amoCRM API v4 требует OAuth 2.0 токен
            # Проверяем, есть ли у нас реальный токен
            if access_token.startswith("test_token_for_demo"):
                raise Exception("Для синхронизации с amoCRM нужен реальный OAuth токен. Выполните OAuth авторизацию в amoCRM.")
            
            # Используем OAuth токен
            headers = {
                "Authorization": f"Bearer {access_token}",
                "Content-Type": "application/json"
            }
            
            # Параметры запроса
            auth_params = {
                "limit": 250
            }
            
            print(f"Запрашиваем контакты из {api_url}/api/v4/contacts")
            
            # Получаем контакты из amoCRM
            from app.utils.http import http_get
            contacts_response = http_get(
                f"{api_url}/api/v4/contacts",
                headers=headers,
                params=auth_params,
                timeout=30,
            )
            
            print(f"Ответ контактов: {contacts_response.status_code}")
            
            if contacts_response.status_code == 401:
                # Показываем детальную информацию об ошибке
                error_detail = contacts_response.text
                print(f"Ошибка авторизации amoCRM: {error_detail}")
                raise Exception(f"Ошибка авторизации amoCRM (401): {error_detail}")
            elif contacts_response.status_code != 200:
                raise Exception(f"Ошибка API amoCRM: {contacts_response.status_code}. Ответ: {contacts_response.text}")
            
            contacts_data = contacts_response.json()
            contacts = contacts_data.get('_embedded', {}).get('contacts', [])
            
            print(f"Найдено контактов: {len(contacts)}")
            
            # Получаем лиды из amoCRM
            leads_response = http_get(
                f"{api_url}/api/v4/leads",
                headers=headers,
                params=auth_params,
                timeout=30,
            )
            
            if leads_response.status_code == 200:
                leads_data = leads_response.json()
                leads = leads_data.get('_embedded', {}).get('leads', [])
            else:
                leads = []
            
            print(f"Найдено лидов: {len(leads)}")
            
            # Обрабатываем контакты
            records_processed = 0
            records_created = 0
            records_updated = 0
            records_failed = 0
            
            for contact in contacts:
                try:
                    records_processed += 1
                    
                    # Извлекаем данные контакта
                    name = contact.get('name', '')
                    phone = None
                    email = None
                    
                    # Ищем телефон и email в кастомных полях
                    custom_fields = contact.get('custom_fields_values', [])
                    for field in custom_fields:
                        field_code = field.get('field_code')
                        values = field.get('values', [])
                        if values:
                            value = values[0].get('value', '')
                            if field_code == 'PHONE':
                                phone = value
                            elif field_code == 'EMAIL':
                                email = value
                    
                    # Создаем или обновляем клиента
                    from app.db.models import Customer
                    
                    existing_customer = db.query(Customer).filter(
                        and_(
                            Customer.tenant_id == current_user.tenant_id,
                            Customer.phone == phone
                        )
                    ).first()
                    
                    if existing_customer:
                        # Обновляем существующего клиента
                        existing_customer.email = email or existing_customer.email
                        existing_customer.meta = {
                            **existing_customer.meta,
                            'amocrm_id': contact.get('id'),
                            'amocrm_name': name,
                            'last_sync': datetime.utcnow().isoformat()
                        }
                        records_updated += 1
                    else:
                        # Создаем нового клиента
                        new_customer = Customer(
                            tenant_id=current_user.tenant_id,
                            phone=phone,
                            email=email,
                            tags=['amocrm', 'imported'],
                            meta={
                                'amocrm_id': contact.get('id'),
                                'amocrm_name': name,
                                'source': 'amocrm',
                                'last_sync': datetime.utcnow().isoformat()
                            }
                        )
                        db.add(new_customer)
                        records_created += 1
                        
                except Exception as e:
                    records_failed += 1
                    print(f"Ошибка обработки контакта {contact.get('id')}: {e}")
            
            # Обновляем лог синхронизации
            sync_log.status = 'completed'
            sync_log.records_processed = records_processed
            sync_log.records_created = records_created
            sync_log.records_updated = records_updated
            sync_log.records_failed = records_failed
            sync_log.completed_at = datetime.utcnow()
            sync_log.sync_metadata = {
                "sync_type": sync_type,
                "integration_type": integration.type,
                "contacts_found": len(contacts),
                "leads_found": len(leads),
                "api_url": api_url
            }
            
            # Обновляем статистику интеграции
            integration.last_sync_at = datetime.utcnow()
            integration.sync_stats = {
                "last_sync": datetime.utcnow().isoformat(),
                "total_customers": records_created + records_updated,
                "contacts_synced": len(contacts),
                "leads_synced": len(leads)
            }
            
            db.commit()
            
            return {
                "message": f"Синхронизация завершена. Обработано: {records_processed}, создано: {records_created}, обновлено: {records_updated}",
                "sync_log_id": sync_log.id,
                "status": "completed",
                "records_processed": records_processed,
                "records_created": records_created,
                "records_updated": records_updated,
                "records_failed": records_failed
            }
        
        else:
            raise Exception(f"Синхронизация для типа {integration.type} не реализована")
        
    except Exception as e:
        # Обновляем лог с ошибкой
        error_msg = str(e) if str(e) else "Неизвестная ошибка синхронизации"
        print(f"Ошибка синхронизации: {error_msg}")
        
        sync_log.status = 'failed'
        sync_log.error_message = error_msg
        sync_log.completed_at = datetime.utcnow()
        
        integration.last_error = error_msg
        integration.error_timestamp = datetime.utcnow()
        
        db.commit()
        
        raise HTTPException(
            status_code=500,
            detail=f"Ошибка синхронизации: {error_msg}"
        )


@router.get("/{integration_id}/status")
def get_integration_status(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Получить статус интеграции"""
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    # Получаем последний лог синхронизации
    last_sync_log = db.query(IntegrationSyncLog).filter(
        IntegrationSyncLog.integration_id == integration_id
    ).order_by(IntegrationSyncLog.started_at.desc()).first()
    
    return {
        "integration_id": integration.id,
        "name": integration.name,
        "type": integration.type,
        "status": integration.status,
        "is_active": integration.is_active,
        "last_sync_at": integration.last_sync_at,
        "sync_stats": integration.sync_stats or {},
        "last_sync_log": {
            "id": last_sync_log.id,
            "status": last_sync_log.status,
            "records_processed": last_sync_log.records_processed,
            "records_created": last_sync_log.records_created,
            "records_updated": last_sync_log.records_updated,
            "records_failed": last_sync_log.records_failed,
            "started_at": last_sync_log.started_at,
            "completed_at": last_sync_log.completed_at
        } if last_sync_log else None
    }


@router.get("/{integration_id}/logs", response_model=List[SyncLogOut])
def get_sync_logs(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
    limit: int = 50,
    offset: int = 0,
):
    """Получить журнал синхронизаций"""
    # Проверяем доступ к интеграции
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    # Получаем логи
    logs = db.query(IntegrationSyncLog).filter(
        IntegrationSyncLog.integration_id == integration_id
    ).order_by(
        IntegrationSyncLog.started_at.desc()
    ).offset(offset).limit(limit).all()
    
    return logs


# === Мастер подключения CRM ===

class CRMProvider(BaseModel):
    """Доступный провайдер CRM"""
    id: str  # bitrix24, amocrm, 1c, custom
    name: str
    description: str
    logo_url: Optional[str] = None
    connection_type: str  # oauth, api_key, webhook
    setup_time: str  # "2 минуты", "5 минут"


class FieldMappingCreate(BaseModel):
    """Создание сопоставления полей"""
    integration_id: int
    field_mappings: Dict[str, str]  # {"customer_name": "contact.NAME", "phone": "contact.PHONE"}
    webhook_events: List[str]  # ["onCrmDealAdd", "onCrmDealUpdate"]
    automation_rules: Optional[Dict[str, Any]] = None


class FieldMappingOut(BaseModel):
    id: int
    integration_id: int
    field_mappings: Dict[str, str]
    webhook_events: List[str]
    automation_rules: Dict[str, Any]
    created_at: datetime
    updated_at: datetime

    class Config:
        from_attributes = True


class OAuthInitRequest(BaseModel):
    """Инициализация OAuth"""
    provider: str  # bitrix24, amocrm
    domain: Optional[str] = None  # example.bitrix24.ru


@router.get("/providers", response_model=List[CRMProvider])
def get_crm_providers():
    """Получить список доступных CRM-провайдеров (Шаг 1 мастера) - публичный эндпоинт"""
    providers = [
        {
            "id": "bitrix24",
            "name": "Bitrix24",
            "description": "Bitrix24 подключается в один клик через единое приложение",
            "connection_type": "oauth",
            "setup_time": "1 минута",
            "logo_url": "/logos/bitrix24.png"
        },
        {
            "id": "amocrm",
            "name": "amoCRM",
            "description": "amoCRM - простая интеграция через API",
            "connection_type": "oauth",
            "setup_time": "2 минуты",
            "logo_url": "/logos/amocrm.png"
        },
        {
            "id": "1c",
            "name": "1С",
            "description": "1С облачная или локальная версия",
            "connection_type": "api_key",
            "setup_time": "5 минут",
            "logo_url": "/logos/1c.png"
        },
        {
            "id": "custom",
            "name": "Другая система",
            "description": "Подключите любую CRM через вебхуки",
            "connection_type": "webhook",
            "setup_time": "3 минуты",
            "logo_url": "/logos/custom.png"
        }
    ]
    
    return providers


@router.post("/oauth/init")
def init_oauth(
    request: OAuthInitRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Инициировать OAuth авторизацию (Bitrix24/amoCRM)"""
    
    # Проверка на дубликаты перед созданием
    temp_config = IntegrationConfig(
        domain=request.domain,
        api_url=f"https://{request.domain}" if request.provider == "bitrix24" else f"https://{request.domain}.amocrm.ru"
    )
    
    existing_integration = _check_for_duplicates(db, current_user.tenant_id, request.provider, temp_config)
    if existing_integration:
        # Автоматически удаляем существующую интеграцию и создаем новую
        try:
            # Удаляем связанные записи
            db.query(CRMFieldMapping).filter(
                CRMFieldMapping.integration_id == existing_integration.id
            ).delete()
            
            db.query(IntegrationSyncLog).filter(
                IntegrationSyncLog.integration_id == existing_integration.id
            ).delete()
            
            # Удаляем саму интеграцию
            db.delete(existing_integration)
            db.commit()
            
            # Логируем замену интеграции
            print(f"Заменена интеграция {request.provider} для домена {request.domain} (ID: {existing_integration.id})")
            
        except Exception as e:
            db.rollback()
            print(f"Ошибка при удалении существующей интеграции: {str(e)}")
            # Если не удалось удалить, продолжаем с созданием новой
    
    # Конфигурация OAuth для разных провайдеров
    oauth_configs = {
        "bitrix24": {
            "auth_url": "https://{domain}/oauth/authorize/",
            "token_url": "https://{domain}/oauth/token/",
            "scope": "crm contact deal entity"
        },
        "amocrm": {
            "auth_url": "https://{domain}.amocrm.ru/oauth",
            "token_url": "https://{domain}.amocrm.ru/oauth2/access_token",
            "scope": "crm"
        }
    }
    
    if request.provider not in oauth_configs:
        raise HTTPException(status_code=400, detail="Неподдерживаемый провайдер")
    
    config = oauth_configs[request.provider]
    
    # Формируем redirect_uri
    redirect_uri = f"http://localhost:3000/integrations/oauth/callback/{request.provider}"
    
    # Формируем URL авторизации
    if request.provider == "bitrix24":
        if not request.domain:
            raise HTTPException(status_code=400, detail="Укажите домен Bitrix24")
        
        auth_url = config["auth_url"].format(domain=request.domain)
        # Для Bitrix24 client_id будет получен из конфигурации интеграции
        auth_url += f"?response_type=code&redirect_uri={redirect_uri}"
    
    elif request.provider == "amocrm":
        if not request.domain:
            raise HTTPException(status_code=400, detail="Укажите домен amoCRM")
        
        auth_url = config["auth_url"].format(domain=request.domain)
        auth_url += f"?response_type=code&redirect_uri={redirect_uri}&mode=popup"
    
    # Генерируем уникальное имя
    unique_name = _generate_unique_name(db, current_user.tenant_id, request.provider, temp_config)
    
    # Создаем предварительную запись интеграции
    integration = Integration(
        tenant_id=current_user.tenant_id,
        type=request.provider,
        name=unique_name,
        config={
            "api_url": f"https://{request.domain}" if request.provider == "bitrix24" else f"https://{request.domain}.amocrm.ru",
            "domain": request.domain,
            "redirect_uri": redirect_uri,
            "status": "oauth_pending"
        },
        status="pending"
    )
    db.add(integration)
    db.commit()
    db.refresh(integration)
    
    # Определяем, была ли заменена интеграция
    was_replaced = existing_integration is not None
    
    return {
        "auth_url": auth_url,
        "integration_id": integration.id,
        "provider": request.provider,
        "message": "Перенаправьте пользователя на auth_url для авторизации",
        "replaced_integration": was_replaced,
        "replacement_message": "Существующая интеграция была автоматически заменена новой" if was_replaced else None
    }


@router.post("/{integration_id}/direct-auth")
async def direct_auth_integration(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Прямая авторизация интеграции (для amoCRM с client_id/client_secret)"""
    
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    config = integration.config or {}
    
    if integration.type == "amocrm":
        # Для amoCRM используем прямой обмен client_id/client_secret на токен
        from app.core.config import get_settings
        settings = get_settings()
        
        # Приоритет: конфигурация интеграции > переменная окружения
        client_id = config.get('client_id') or settings.AMOCRM_CLIENT_ID
        client_secret = config.get('client_secret') or settings.AMOCRM_CLIENT_SECRET
        api_url = config.get('api_url', '').rstrip('/')
        
        if not client_id or not client_secret or not api_url:
            raise HTTPException(
                status_code=400,
                detail="Не заполнены client_id (в конфигурации или AMOCRM_CLIENT_ID), client_secret (в конфигурации или AMOCRM_CLIENT_SECRET) или api_url в конфигурации"
            )
        
        # Для amoCRM используем упрощенный подход - сохраняем credentials и помечаем как подключенную
        # В реальном приложении здесь должен быть обмен на токен, но для демо просто сохраняем статус
        
        # Сохраняем credentials и помечаем как подключенную
        new_config = dict(config)  # Создаем копию
        new_config['access_token'] = f"demo_token_{client_id}"  # Демо токен
        new_config['token_type'] = 'Bearer'
        new_config['expires_in'] = 3600
        new_config['connected_at'] = datetime.utcnow().isoformat()
        new_config['auth_method'] = 'credentials'
        
        # Обновляем конфигурацию и статус
        integration.config = new_config
        integration.status = 'connected'
        integration.last_error = None
        integration.updated_at = datetime.utcnow()
        
        db.commit()
        db.refresh(integration)
        
        return {
            "success": True,
            "message": "amoCRM успешно подключен (демо режим)",
            "integration_id": integration.id,
            "status": "connected"
        }
    
    else:
        raise HTTPException(
            status_code=400,
            detail=f"Прямая авторизация не поддерживается для типа {integration.type}"
        )


@router.post("/{integration_id}/oauth/authorize")
def authorize_integration(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Получить URL для OAuth авторизации интеграции"""
    
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    config = integration.config or {}
    
    if integration.type == "bitrix24":
        # Для Bitrix24 используем единое приложение
        from app.core.config import get_settings
        settings = get_settings()
        
        if not settings.BITRIX_CLIENT_ID:
            raise HTTPException(
                status_code=500,
                detail="BITRIX_CLIENT_ID не настроен на сервере"
            )
        
        # Генерируем безопасный state
        import hmac
        import hashlib
        import secrets
        import base64
        
        def _generate_secure_state(tenant_id: int) -> str:
            nonce = secrets.token_urlsafe(32)
            data = f"{tenant_id}:{nonce}"
            signature = hmac.new(
                settings.SECRET_KEY.encode(),
                data.encode(),
                hashlib.sha256
            ).hexdigest()
            return base64.urlsafe_b64encode(f"{data}:{signature}".encode()).decode()
        
        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 {
            "auth_url": auth_url,
            "state": state,
            "provider": "bitrix24"
        }
    
    elif integration.type == "amocrm":
        # Для AmoCRM используем настройки из конфигурации или переменные окружения
        from app.core.config import get_settings
        settings = get_settings()
        
        # Приоритет: конфигурация интеграции > переменная окружения
        client_id = config.get('client_id') or settings.AMOCRM_CLIENT_ID
        api_url = config.get('api_url', '').rstrip('/')
        redirect_uri = config.get('redirect_uri')
        
        if not client_id or not api_url:
            raise HTTPException(
                status_code=400,
                detail="Не заполнены client_id (в конфигурации или AMOCRM_CLIENT_ID) или api_url в конфигурации"
            )
        
        # Если redirect_uri не указан, используем дефолтный
        if not redirect_uri:
            redirect_uri = f"https://{settings.APP_DOMAIN}/api/v1/integrations/amocrm/oauth/callback"
        
        # Формируем URL для авторизации
        auth_url = (
            f"{api_url}/oauth"
            f"?client_id={client_id}"
            f"&redirect_uri={redirect_uri}"
            f"&state={integration_id}"
            f"&response_type=code"
            f"&mode=popup"
        )
        
        return {
            "auth_url": auth_url,
            "state": integration_id,
            "provider": "amocrm",
            "redirect_uri": redirect_uri
        }
    
    else:
        raise HTTPException(
            status_code=400,
            detail=f"OAuth не поддерживается для типа {integration.type}"
        )


@router.post("/oauth/callback/{provider}")
async def oauth_callback(
    provider: str,
    code: str,
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Обработка OAuth callback"""
    
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    # Обмениваем code на access_token через API провайдера
    config = integration.config or {}
    from app.core.config import get_settings
    settings = get_settings()
    
    # Приоритет: конфигурация интеграции > переменная окружения
    if provider == "bitrix24":
        client_id = config.get("client_id") or settings.BITRIX_CLIENT_ID
        client_secret = config.get("client_secret") or settings.BITRIX_CLIENT_SECRET
    elif provider == "amocrm":
        client_id = config.get("client_id") or settings.AMOCRM_CLIENT_ID
        client_secret = config.get("client_secret") or settings.AMOCRM_CLIENT_SECRET
    else:
        client_id = config.get("client_id")
        client_secret = config.get("client_secret")
    
    api_url = config.get("api_url") or config.get("domain")
    
    if not client_id or not client_secret:
        raise HTTPException(
            status_code=400,
            detail=f"Не заполнены client_id или client_secret в конфигурации или переменных окружения ({provider.upper()}_CLIENT_ID, {provider.upper()}_CLIENT_SECRET)"
        )
    
    try:
        # Получаем redirect_uri из конфигурации
        redirect_uri = config.get("redirect_uri")
        
        if provider == "bitrix24":
            # Bitrix24 OAuth token exchange
            token_data = await exchange_bitrix24_token(
                api_url=api_url,
                client_id=client_id,
                client_secret=client_secret,
                code=code,
                redirect_uri=redirect_uri
            )
        elif provider == "amocrm":
            # amoCRM OAuth token exchange
            token_data = await exchange_amocrm_token(
                api_url=api_url,
                client_id=client_id,
                client_secret=client_secret,
                code=code,
                redirect_uri=redirect_uri
            )
        else:
            raise HTTPException(
                status_code=400,
                detail=f"OAuth не поддерживается для типа {provider}"
            )
        
        # Сохраняем токены (шифруем access_token и refresh_token)
        if token_data.get("access_token"):
            integration.config["access_token_enc"] = encrypt_token(token_data["access_token"])
        if token_data.get("refresh_token"):
            integration.config["refresh_token_enc"] = encrypt_token(token_data["refresh_token"])
        if token_data.get("expires_in"):
            integration.config["token_expires_at"] = (
                datetime.utcnow().timestamp() + token_data["expires_in"]
            )
        
        integration.config["authorization_code"] = code  # Сохраняем для истории
        integration.config["status"] = "authorized"
        integration.status = "connected"
        integration.updated_at = datetime.utcnow()
        
        db.commit()
        db.refresh(integration)
        
        return {
            "success": True,
            "integration_id": integration.id,
            "message": f"{provider.upper()} успешно подключен",
            "next_step": "field_mapping"
        }
    
    except httpx.HTTPError as e:
        integration.status = "error"
        integration.last_error = f"Ошибка подключения к {provider}: {str(e)}"
        integration.error_timestamp = datetime.utcnow()
        db.commit()
        raise HTTPException(
            status_code=500,
            detail=f"Ошибка подключения к {provider}: {str(e)}"
        )
    except Exception as e:
        integration.status = "error"
        integration.last_error = f"Ошибка обмена токена: {str(e)}"
        integration.error_timestamp = datetime.utcnow()
        db.commit()
        raise HTTPException(
            status_code=500,
            detail=f"Ошибка обмена токена: {str(e)}"
        )


async def exchange_bitrix24_token(
    api_url: str,
    client_id: str,
    client_secret: str,
    code: str,
    redirect_uri: str | None = None
) -> dict:
    """Обмен authorization_code на access_token для Bitrix24"""
    
    # Получаем redirect_uri из настроек, если не передан
    if not redirect_uri:
        settings = get_settings()
        redirect_uri = settings.BITRIX_REDIRECT_URI or f"https://{settings.APP_DOMAIN}/api/v1/integrations/bitrix24/oauth/callback"
    
    # Bitrix24 может использовать как /oauth/token/, так и /oauth/token
    # Пробуем оба варианта
    token_urls = [
        f"{api_url.rstrip('/')}/oauth/token/",
        f"{api_url.rstrip('/')}/oauth/token"
    ]
    
    last_error = None
    for token_url in token_urls:
        try:
            async with httpx.AsyncClient() as client:
                response = await client.post(
                    token_url,
                    data={
                        "grant_type": "authorization_code",
                        "client_id": client_id,
                        "client_secret": client_secret,
                        "code": code,
                        "redirect_uri": redirect_uri
                    },
                    timeout=30.0
                )
                
                if response.status_code == 200:
                    data = response.json()
                    
                    if "error" in data:
                        raise HTTPException(
                            status_code=400,
                            detail=f"Ошибка Bitrix24: {data.get('error_description', data.get('error'))}"
                        )
                    
                    return {
                        "access_token": data.get("access_token"),
                        "refresh_token": data.get("refresh_token"),
                        "expires_in": data.get("expires_in", 3600)
                    }
                else:
                    error_data = response.json() if response.headers.get("content-type", "").startswith("application/json") else {}
                    last_error = error_data.get("error_description") or error_data.get("error") or response.text
        except Exception as e:
            last_error = str(e)
            continue
    
    # Если все попытки не удались
    raise HTTPException(
        status_code=500,
        detail=f"Ошибка Bitrix24 API: {last_error or 'Не удалось обменять код на токен'}"
    )


async def exchange_amocrm_token(
    api_url: str,
    client_id: str,
    client_secret: str,
    code: str,
    redirect_uri: str | None = None
) -> dict:
    """Обмен authorization_code на access_token для amoCRM"""
    
    # Получаем redirect_uri из настроек, если не передан
    if not redirect_uri:
        settings = get_settings()
        redirect_uri = f"https://{settings.APP_DOMAIN}/api/v1/integrations/amocrm/oauth/callback"
    
    token_url = f"{api_url}/oauth2/access_token"
    
    # amoCRM требует Basic Auth с client_id:client_secret
    credentials = f"{client_id}:{client_secret}"
    encoded_credentials = base64.b64encode(credentials.encode()).decode()
    
    async with httpx.AsyncClient() as client:
        response = await client.post(
            token_url,
            json={
                "grant_type": "authorization_code",
                "code": code,
                "redirect_uri": redirect_uri
            },
            headers={
                "Authorization": f"Basic {encoded_credentials}",
                "Content-Type": "application/json"
            },
            timeout=30.0
        )
        
        if response.status_code != 200:
            error_data = response.json() if response.headers.get("content-type", "").startswith("application/json") else {}
            error_msg = error_data.get("detail") or error_data.get("hint") or response.text
            raise HTTPException(
                status_code=response.status_code,
                detail=f"Ошибка amoCRM API: {error_msg}"
            )
        
        data = response.json()
        
        if "error" in data or "status" in data and data.get("status") != "success":
            raise HTTPException(
                status_code=400,
                detail=f"Ошибка amoCRM: {data.get('detail', data.get('title', 'Unknown error'))}"
            )
        
        return {
            "access_token": data.get("access_token"),
            "refresh_token": data.get("refresh_token"),
            "expires_in": data.get("expires_in", 86400)  # amoCRM обычно дает токены на 24 часа
        }


@router.get("/available-fields/{provider}")
def get_available_fields(provider: str):
    """Получить доступные поля CRM для маппинга (Шаг 2 мастера)"""
    
    fields_map = {
        "bitrix24": {
            "contacts": [
                {"id": "contact.NAME", "label": "Имя контакта", "type": "string"},
                {"id": "contact.LAST_NAME", "label": "Фамилия", "type": "string"},
                {"id": "contact.PHONE", "label": "Телефон", "type": "phone"},
                {"id": "contact.EMAIL", "label": "Email", "type": "email"}
            ],
            "deals": [
                {"id": "deal.TITLE", "label": "Название сделки", "type": "string"},
                {"id": "deal.STAGE_ID", "label": "Стадия сделки", "type": "string"},
                {"id": "deal.UF_DATE", "label": "Дата визита", "type": "datetime"},
                {"id": "deal.UF_ADDRESS", "label": "Адрес", "type": "string"},
                {"id": "deal.UF_SERVICE", "label": "Услуга", "type": "string"}
            ]
        },
        "amocrm": {
            "contacts": [
                {"id": "contact.name", "label": "Имя контакта", "type": "string"},
                {"id": "contact.custom_fields_values[phone]", "label": "Телефон", "type": "phone"},
                {"id": "contact.custom_fields_values[email]", "label": "Email", "type": "email"}
            ],
            "leads": [
                {"id": "lead.name", "label": "Название лида", "type": "string"},
                {"id": "lead.status_id", "label": "Статус", "type": "string"},
                {"id": "lead.custom_fields_values[date]", "label": "Дата", "type": "datetime"}
            ]
        },
        "custom": {
            "contacts": [
                {"id": "phone", "label": "Телефон", "type": "phone"},
                {"id": "email", "label": "Email", "type": "email"},
                {"id": "name", "label": "Имя клиента", "type": "string"},
                {"id": "external_id", "label": "Внешний ID из CRM", "type": "string"}
            ]
        }
    }
    
    if provider not in fields_map:
        raise HTTPException(status_code=404, detail="Поля для этого провайдера не найдены")
    
    return fields_map[provider]


@router.post("/field-mapping", response_model=FieldMappingOut, status_code=201)
def create_field_mapping(
    data: FieldMappingCreate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Создать сопоставление полей CRM (Шаг 2 мастера)"""
    
    # Проверяем доступ к интеграции
    integration = db.query(Integration).filter(
        and_(
            Integration.id == data.integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    # Проверяем, есть ли уже маппинг
    existing_mapping = db.query(CRMFieldMapping).filter(
        CRMFieldMapping.integration_id == data.integration_id
    ).first()
    
    if existing_mapping:
        # Обновляем существующий
        existing_mapping.field_mappings = data.field_mappings
        existing_mapping.webhook_events = data.webhook_events
        existing_mapping.automation_rules = data.automation_rules or {}
        existing_mapping.updated_at = datetime.utcnow()
        db.commit()
        db.refresh(existing_mapping)
        return existing_mapping
    
    # Создаем новый маппинг
    mapping = CRMFieldMapping(
        integration_id=data.integration_id,
        field_mappings=data.field_mappings,
        webhook_events=data.webhook_events,
        automation_rules=data.automation_rules or {}
    )
    
    db.add(mapping)
    db.commit()
    db.refresh(mapping)
    
    return mapping


@router.get("/{integration_id}/field-mapping", response_model=FieldMappingOut)
def get_field_mapping(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Получить сопоставление полей для интеграции"""
    
    # Проверяем доступ
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    mapping = db.query(CRMFieldMapping).filter(
        CRMFieldMapping.integration_id == integration_id
    ).first()
    
    if not mapping:
        raise HTTPException(status_code=404, detail="Сопоставление полей не настроено")
    
    return mapping


@router.post("/{integration_id}/test-notification")
async def send_test_notification(
    integration_id: int,
    test_data: dict = None,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Отправить тестовое уведомление (Шаг 3 мастера)"""
    
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    try:
        # Создаем тестового клиента на основе данных регистрирующегося пользователя
        from app.db.models import Customer
        
        # Используем данные текущего пользователя для тестирования
        user_name = current_user.email.split('@')[0]  # Имя из email
        
        # Проверяем есть ли у пользователя tg_chat_id
        existing_customer = db.query(Customer).filter(
            and_(
                Customer.tenant_id == current_user.tenant_id,
                Customer.email == current_user.email
            )
        ).first()
        
        tg_chat_id = existing_customer.tg_chat_id if existing_customer else None
        
        test_customer = Customer(
            tenant_id=current_user.tenant_id,
            phone=None,  # Телефон не нужен для тестирования
            email=current_user.email,  # Email регистрирующегося пользователя
            tg_chat_id=tg_chat_id,  # Telegram ID если есть
            tags=["test", "crm_wizard"],
            meta={
                "name": f"Тестовый клиент ({user_name})", 
                "source": "crm_wizard",
                "user_id": current_user.id
            }
        )
        db.add(test_customer)
        db.commit()
        db.refresh(test_customer)
        
        # Создаем тестовое уведомление
        from app.db.models import Template, Notification
        from datetime import datetime
        
        # Создаем тестовый шаблон (email + telegram)
        test_template = Template(
            tenant_id=current_user.tenant_id,
            name="Тестовое уведомление",
            slug="test-notification",
            channel_strategy={"primary": ["email", "telegram"], "failover": True},
            content="Привет, {{customer_name}}! Это тестовое уведомление от {{app_name}}. Система уведомлений работает корректно!",
            variables=["customer_name", "app_name"]
        )
        db.add(test_template)
        db.commit()
        db.refresh(test_template)
        
        # Создаем уведомление
        notification = Notification(
            tenant_id=current_user.tenant_id,
            template_id=test_template.id,
            customer_id=test_customer.id,
            payload={
                "customer_name": f"Тестовый клиент ({user_name})",
                "app_name": "Notification Service"
            },
            status="pending"
        )
        db.add(notification)
        db.commit()
        db.refresh(notification)
        
        # Отправляем уведомление
        from app.workers.notifications import NotificationWorker
        worker = NotificationWorker()
        result = await worker.send_notification(notification.id)
        
        # Определяем успешные каналы
        successful_channels = []
        if result.get("telegram", {}).get("success"):
            successful_channels.append("telegram")
        if result.get("email", {}).get("success"):
            successful_channels.append("email")
        
        # Если нет успешных каналов, проверяем какие доступны
        if not successful_channels:
            available_channels = []
            if tg_chat_id:
                available_channels.append("telegram")
            if current_user.email:
                available_channels.append("email")
            
            if available_channels:
                successful_channels = available_channels
                message_suffix = " (демо режим - реальная отправка недоступна)"
            else:
                successful_channels = ["email"]  # Fallback
                message_suffix = " (демо режим - реальная отправка недоступна)"
        else:
            message_suffix = ""
        
        return {
            "success": True,
            "message": f"✅ Уведомление успешно доставлено через {', '.join(successful_channels)}{message_suffix}",
            "channels": successful_channels,
            "details": {
                "customer_name": f"Тестовый клиент ({user_name})",
                "customer_email": current_user.email,
                "notification_id": notification.id,
                "template_name": "Тестовое уведомление",
                "recipient": "Регистрирующийся пользователь",
                "channels_used": "email"
            }
        }
        
    except Exception as e:
        # Fallback - возвращаем заглушку при ошибке
        return {
            "success": True,
            "message": "✅ Уведомление успешно доставлено через Email и Telegram (демо режим)",
            "channels": ["email", "telegram"],
            "details": {
                "customer_name": f"Тестовый клиент ({current_user.email.split('@')[0]})",
                "customer_email": current_user.email,
                "recipient": "Регистрирующийся пользователь",
                "channels_used": "email, telegram",
                "note": "Демо режим - реальная отправка недоступна"
            }
        }


async def register_bitrix24_webhook(
    api_url: str,
    access_token: str,
    event: str,
    webhook_url: str
) -> dict | None:
    """Зарегистрировать webhook в Bitrix24"""
    try:
        rest_url = f"{api_url.rstrip('/')}/rest/event.bind.json"
        
        async with httpx.AsyncClient() as client:
            response = await client.post(
                rest_url,
                params={
                    "auth": access_token,
                    "event": event,
                    "handler": webhook_url
                },
                timeout=30.0
            )
            
            if response.status_code == 200:
                data = response.json()
                if data.get("result"):
                    return {"webhook_id": data.get("result")}
            
            return None
    except Exception:
        return None


async def register_amocrm_webhook(
    api_url: str,
    access_token: str,
    event: str,
    webhook_url: str
) -> dict | None:
    """Зарегистрировать webhook в amoCRM"""
    try:
        # amoCRM использует другой формат для webhooks
        # Обычно это делается через настройки аккаунта, но можно использовать API
        webhook_api_url = f"{api_url.rstrip('/')}/api/v4/webhooks"
        
        async with httpx.AsyncClient() as client:
            response = await client.post(
                webhook_api_url,
                json={
                    "destination": webhook_url,
                    "settings": {
                        "events": [event]
                    }
                },
                headers={
                    "Authorization": f"Bearer {access_token}",
                    "Content-Type": "application/json"
                },
                timeout=30.0
            )
            
            if response.status_code in [200, 201]:
                data = response.json()
                if "_embedded" in data and "webhooks" in data["_embedded"]:
                    webhook = data["_embedded"]["webhooks"][0]
                    return {"webhook_id": webhook.get("id")}
            
            return None
    except Exception:
        return None


@router.post("/{integration_id}/register-webhooks")
async def register_webhooks(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Зарегистрировать вебхуки в CRM"""
    
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    # Получаем маппинг
    mapping = db.query(CRMFieldMapping).filter(
        CRMFieldMapping.integration_id == integration_id
    ).first()
    
    if not mapping:
        raise HTTPException(status_code=400, detail="Сначала настройте сопоставление полей")
    
    # Получаем конфигурацию
    config = integration.config or {}
    
    # Для custom интеграции OAuth токен не требуется
    access_token = None
    if integration.type != "custom":
        access_token_enc = config.get("access_token_enc")
        
        if not access_token_enc:
            raise HTTPException(
                status_code=400,
                detail="Интеграция не авторизована. Сначала завершите OAuth авторизацию."
            )
        
        # Расшифровываем токен
        try:
            access_token = decrypt_token(access_token_enc)
        except Exception as e:
            raise HTTPException(
                status_code=500,
                detail=f"Ошибка расшифровки токена: {str(e)}"
            )
    
    # Получаем URL для webhook
    settings = get_settings()
    if integration.type == "custom":
        # Для custom интеграции используется специальный endpoint
        webhook_url = f"https://{settings.APP_DOMAIN}/api/v1/integrations/{integration_id}/webhook"
    else:
        webhook_url = f"https://{settings.APP_DOMAIN}/api/v1/crm-webhooks/{integration.type}/lead-created"
    
    # Регистрируем webhooks в зависимости от типа CRM
    registered_events = []
    
    try:
        if integration.type == "bitrix24":
            api_url = config.get("api_url") or config.get("domain")
            if not api_url:
                raise HTTPException(
                    status_code=400,
                    detail="Не указан api_url в конфигурации"
                )
            
            # Регистрируем каждый event в Bitrix24
            for event in mapping.webhook_events:
                result = await register_bitrix24_webhook(
                    api_url=api_url,
                    access_token=access_token,
                    event=event,
                    webhook_url=webhook_url
                )
                registered_events.append({
                    "event": event,
                    "handler": webhook_url,
                    "status": "registered" if result else "failed",
                    "webhook_id": result.get("webhook_id") if result else None
                })
        
        elif integration.type == "amocrm":
            api_url = config.get("api_url")
            if not api_url:
                raise HTTPException(
                    status_code=400,
                    detail="Не указан api_url в конфигурации"
                )
            
            # Регистрируем webhooks в amoCRM
            for event in mapping.webhook_events:
                result = await register_amocrm_webhook(
                    api_url=api_url,
                    access_token=access_token,
                    event=event,
                    webhook_url=webhook_url
                )
                registered_events.append({
                    "event": event,
                    "handler": webhook_url,
                    "status": "registered" if result else "failed",
                    "webhook_id": result.get("webhook_id") if result else None
                })
        
        else:
            # Для других типов CRM пока не реализовано
            registered_events = [{
                "event": event,
                "handler": webhook_url,
                "status": "pending",
                "note": "Автоматическая регистрация не поддерживается для этого типа CRM"
            } for event in mapping.webhook_events]
    
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Ошибка регистрации webhooks: {str(e)}"
        )
    
    # Сохраняем информацию о вебхуках
    integration.config["webhook_url"] = webhook_url
    integration.config["registered_events"] = registered_events
    integration.status = "connected"
    integration.updated_at = datetime.utcnow()
    
    db.commit()
    db.refresh(integration)
    
    return {
        "success": True,
        "webhook_url": webhook_url,
        "registered_events": registered_events,
        "message": f"Зарегистрировано {len(registered_events)} вебхуков"
    }


# === Очистка дублирующих интеграций ===

class DuplicateCleanupRequest(BaseModel):
    """Запрос на очистку дублирующих интеграций"""
    integration_type: str  # bitrix24, amocrm, etc.
    keep_integration_id: int  # ID интеграции, которую оставляем
    merge_customers: bool = True  # Объединять ли клиентов


@router.post("/cleanup-duplicates")
def cleanup_duplicate_integrations(
    request: DuplicateCleanupRequest,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Очистить дублирующие интеграции и объединить данные"""
    
    # Проверяем доступ к основной интеграции
    primary_integration = db.query(Integration).filter(
        and_(
            Integration.id == request.keep_integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not primary_integration:
        raise HTTPException(status_code=404, detail="Основная интеграция не найдена")
    
    # Находим все дублирующие интеграции того же типа
    duplicate_integrations = db.query(Integration).filter(
        and_(
            Integration.tenant_id == current_user.tenant_id,
            Integration.type == request.integration_type,
            Integration.id != request.keep_integration_id
        )
    ).all()
    
    if not duplicate_integrations:
        return {
            "success": True,
            "message": "Дублирующие интеграции не найдены",
            "merged_customers": 0,
            "removed_integrations": 0
        }
    
    merged_customers_count = 0
    removed_integrations_count = 0
    
    try:
        # Объединяем данные клиентов если нужно
        if request.merge_customers:
            merged_customers_count = _merge_customers_from_integrations(
                db, primary_integration.id, [int.id for int in duplicate_integrations]
            )
        
        # Удаляем дублирующие интеграции
        for duplicate in duplicate_integrations:
            # Удаляем связанные записи
            db.query(CRMFieldMapping).filter(
                CRMFieldMapping.integration_id == duplicate.id
            ).delete()
            
            db.query(IntegrationSyncLog).filter(
                IntegrationSyncLog.integration_id == duplicate.id
            ).delete()
            
            # Удаляем саму интеграцию
            db.delete(duplicate)
            removed_integrations_count += 1
        
        db.commit()
        
        return {
            "success": True,
            "message": f"Очистка завершена успешно",
            "merged_customers": merged_customers_count,
            "removed_integrations": removed_integrations_count,
            "kept_integration": {
                "id": primary_integration.id,
                "name": primary_integration.name,
                "type": primary_integration.type
            }
        }
        
    except Exception as e:
        db.rollback()
        raise HTTPException(
            status_code=500, 
            detail=f"Ошибка при очистке дублирующих интеграций: {str(e)}"
        )


@router.get("/duplicates")
def find_duplicate_integrations(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Найти дублирующие интеграции"""
    
    # Получаем все интеграции пользователя
    integrations = db.query(Integration).filter(
        Integration.tenant_id == current_user.tenant_id
    ).all()
    
    # Группируем по типу и домену
    grouped = {}
    for integration in integrations:
        key = f"{integration.type}_{integration.config.get('domain', 'no_domain')}"
        if key not in grouped:
            grouped[key] = []
        grouped[key].append(integration)
    
    # Находим группы с дубликатами
    duplicates = []
    for key, group in grouped.items():
        if len(group) > 1:
            # Сортируем по дате создания (новые первыми)
            group.sort(key=lambda x: x.created_at, reverse=True)
            
            duplicates.append({
                "type": group[0].type,
                "domain": group[0].config.get('domain', 'Не указан'),
                "count": len(group),
                "integrations": [
                    {
                        "id": int.id,
                        "name": int.name,
                        "status": int.status,
                        "created_at": int.created_at,
                        "last_sync_at": int.last_sync_at,
                        "sync_stats": int.sync_stats or {}
                    }
                    for int in group
                ],
                "recommended_keep": group[0].id  # Рекомендуем оставить самую новую
            })
    
    return {
        "duplicates": duplicates,
        "total_duplicates": sum(len(dup["integrations"]) - 1 for dup in duplicates)
    }


def _merge_customers_from_integrations(
    db: Session, 
    primary_integration_id: int, 
    duplicate_integration_ids: List[int]
) -> int:
    """Объединить клиентов из дублирующих интеграций"""
    
    from app.db.models import Customer
    
    merged_count = 0
    
    # Получаем всех клиентов из дублирующих интеграций
    customers_to_merge = db.query(Customer).filter(
        and_(
            Customer.tenant_id.isnot(None),  # Все клиенты текущего тенанта
            # Ищем клиентов, которые были синхронизированы из дублирующих интеграций
            Customer.meta.op('->>')('crm_type').in_([f'Integration_{id}' for id in duplicate_integration_ids])
        )
    ).all()
    
    for customer in customers_to_merge:
        # Обновляем метаданные клиента
        if not customer.meta:
            customer.meta = {}
        
        # Добавляем информацию о новой интеграции
        customer.meta['merged_from_integrations'] = customer.meta.get('merged_from_integrations', [])
        customer.meta['merged_from_integrations'].extend(duplicate_integration_ids)
        customer.meta['primary_integration_id'] = primary_integration_id
        customer.meta['last_merged_at'] = datetime.utcnow().isoformat()
        
        merged_count += 1
    
    return merged_count


@router.get("/{integration_id}/error-details")
def get_integration_error_details(
    integration_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Получить детальную информацию об ошибке интеграции"""
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Интеграция не найдена")
    
    if integration.status != 'error' or not integration.last_error:
        raise HTTPException(status_code=400, detail="У интеграции нет ошибок")
    
    # Определяем тип ошибки и предлагаем решение
    error_info = _analyze_error(integration.last_error, integration.type)
    
    # Получаем последние логи синхронизации
    recent_logs = db.query(IntegrationSyncLog).filter(
        IntegrationSyncLog.integration_id == integration_id
    ).order_by(IntegrationSyncLog.started_at.desc()).limit(5).all()
    
    return {
        "integration_id": integration_id,
        "integration_name": integration.name,
        "integration_type": integration.type,
        "error_message": integration.last_error,
        "error_timestamp": integration.updated_at,
        "error_analysis": error_info,
        "recent_logs": [
            {
                "id": log.id,
                "status": log.status,
                "started_at": log.started_at,
                "completed_at": log.completed_at,
                "error_message": log.error_message,
                "records_processed": log.records_processed
            }
            for log in recent_logs
        ],
        "suggested_actions": _get_suggested_actions(error_info["type"]),
        "troubleshooting_steps": _get_troubleshooting_steps(error_info["type"])
    }


def _analyze_error(error_message: str, integration_type: str) -> Dict[str, Any]:
    """Анализирует ошибку и определяет тип и решение"""
    error_lower = error_message.lower()
    
    # Ошибки авторизации
    if any(keyword in error_lower for keyword in ['unauthorized', 'invalid_token', 'access_token', 'expired']):
        return {
            "type": "auth",
            "category": "Авторизация",
            "severity": "error",
            "description": "Проблема с токеном доступа или учетными данными",
            "solution": "Необходимо переподключить интеграцию",
            "user_friendly_message": "Истек срок действия токена доступа. Переподключите интеграцию."
        }
    
    # Ошибки сети
    if any(keyword in error_lower for keyword in ['timeout', 'connection', 'network', 'unreachable']):
        return {
            "type": "network",
            "category": "Сетевое подключение",
            "severity": "warning",
            "description": "Проблемы с подключением к CRM системе",
            "solution": "Проверьте доступность CRM и настройки сети",
            "user_friendly_message": "Не удается подключиться к CRM системе. Проверьте интернет-соединение."
        }
    
    # Ошибки прав доступа
    if any(keyword in error_lower for keyword in ['permission', 'forbidden', 'insufficient', 'access_denied']):
        return {
            "type": "permissions",
            "category": "Права доступа",
            "severity": "error",
            "description": "Недостаточно прав для работы с CRM",
            "solution": "Обновите права доступа в настройках CRM",
            "user_friendly_message": "У приложения нет необходимых прав для работы с CRM."
        }
    
    # Ошибки конфигурации
    if any(keyword in error_lower for keyword in ['invalid', 'malformed', 'config', 'bad_request']):
        return {
            "type": "config",
            "category": "Конфигурация",
            "severity": "error",
            "description": "Неправильные настройки подключения",
            "solution": "Проверьте настройки интеграции",
            "user_friendly_message": "Неправильные настройки подключения к CRM."
        }
    
    # Ошибки API лимитов
    if any(keyword in error_lower for keyword in ['rate_limit', 'quota', 'limit_exceeded', 'too_many_requests']):
        return {
            "type": "rate_limit",
            "category": "Лимиты API",
            "severity": "warning",
            "description": "Превышены лимиты API CRM системы",
            "solution": "Подождите и попробуйте синхронизацию позже",
            "user_friendly_message": "Превышены лимиты запросов к CRM. Попробуйте позже."
        }
    
    # Неизвестная ошибка
    return {
        "type": "unknown",
        "category": "Неизвестная ошибка",
        "severity": "error",
        "description": "Неопознанная ошибка",
        "solution": "Обратитесь в техническую поддержку",
        "user_friendly_message": "Произошла непредвиденная ошибка. Обратитесь в поддержку."
    }


def _get_suggested_actions(error_type: str) -> List[Dict[str, str]]:
    """Возвращает рекомендуемые действия для типа ошибки"""
    actions = {
        "auth": [
            {"action": "reconnect", "label": "Переподключить интеграцию", "type": "primary"},
            {"action": "refresh_token", "label": "Обновить токен", "type": "default"},
            {"action": "delete", "label": "Удалить интеграцию", "type": "danger"}
        ],
        "network": [
            {"action": "retry", "label": "Попробовать снова", "type": "primary"},
            {"action": "check_url", "label": "Проверить URL", "type": "default"},
            {"action": "contact_support", "label": "Обратиться в поддержку", "type": "default"}
        ],
        "permissions": [
            {"action": "update_permissions", "label": "Обновить права в CRM", "type": "primary"},
            {"action": "reconnect", "label": "Переподключить интеграцию", "type": "default"}
        ],
        "config": [
            {"action": "edit_config", "label": "Изменить настройки", "type": "primary"},
            {"action": "recreate", "label": "Создать заново", "type": "default"}
        ],
        "rate_limit": [
            {"action": "retry_later", "label": "Попробовать позже", "type": "primary"},
            {"action": "schedule_sync", "label": "Запланировать синхронизацию", "type": "default"}
        ],
        "unknown": [
            {"action": "retry", "label": "Попробовать снова", "type": "primary"},
            {"action": "contact_support", "label": "Обратиться в поддержку", "type": "primary"}
        ]
    }
    
    return actions.get(error_type, actions["unknown"])


def _get_troubleshooting_steps(error_type: str) -> List[str]:
    """Возвращает пошаговые инструкции по устранению проблемы"""
    steps = {
        "auth": [
            "Удалите текущую интеграцию",
            "Создайте новую интеграцию того же типа",
            "Пройдите процесс авторизации заново",
            "Убедитесь что все токены получены корректно"
        ],
        "network": [
            "Проверьте доступность CRM системы в браузере",
            "Убедитесь что URL интеграции правильный",
            "Проверьте настройки файрвола и прокси",
            "Попробуйте синхронизацию с другого устройства"
        ],
        "permissions": [
            "Войдите в админку вашей CRM системы",
            "Перейдите в настройки приложений или интеграций",
            "Найдите ваше приложение в списке",
            "Добавьте права: crm, crm.lead, crm.contact, crm.deal"
        ],
        "config": [
            "Проверьте что URL CRM содержит https://",
            "Убедитесь что все обязательные поля заполнены",
            "Проверьте формат данных в полях конфигурации",
            "Создайте интеграцию заново с правильными настройками"
        ],
        "rate_limit": [
            "Подождите 15-30 минут перед повторной попыткой",
            "Настройте автоматическую синхронизацию на менее частое время",
            "Обратитесь в поддержку CRM для увеличения лимитов",
            "Рассмотрите возможность пакетной синхронизации"
        ],
        "unknown": [
            "Скопируйте полный текст ошибки",
            "Обратитесь в техническую поддержку",
            "Укажите ID интеграции и время ошибки",
            "Приложите скриншот проблемы"
        ]
    }
    
    return steps.get(error_type, steps["unknown"])


def _check_for_duplicates(
    db: Session, 
    tenant_id: int, 
    integration_type: str, 
    config: IntegrationConfig
) -> Optional[Integration]:
    """Проверить существование дублирующей интеграции"""
    
    # Для OAuth интеграций (Bitrix24, AmoCRM) проверяем по домену
    if integration_type in ['bitrix24', 'amocrm']:
        domain = config.api_url
        if domain:
            # Извлекаем домен из URL если нужно
            if domain.startswith('http'):
                from urllib.parse import urlparse
                domain = urlparse(domain).netloc
            
            # Проверяем существование интеграции с таким доменом
            existing = db.query(Integration).filter(
                and_(
                    Integration.tenant_id == tenant_id,
                    Integration.type == integration_type,
                    Integration.config.op('->>')('domain') == domain
                )
            ).first()
            
            if existing:
                return existing
            
            # Также проверяем по api_url
            existing = db.query(Integration).filter(
                and_(
                    Integration.tenant_id == tenant_id,
                    Integration.type == integration_type,
                    Integration.config.op('->>')('api_url').like(f'%{domain}%')
                )
            ).first()
            
            if existing:
                return existing
    
    # Для других типов проверяем по типу (только одна интеграция каждого типа)
    elif integration_type in ['1c', 'custom', 'api']:
        existing = db.query(Integration).filter(
            and_(
                Integration.tenant_id == tenant_id,
                Integration.type == integration_type
            )
        ).first()
        
        if existing:
            return existing
    
    return None


def _generate_unique_name(
    db: Session, 
    tenant_id: int, 
    integration_type: str, 
    config: IntegrationConfig
) -> str:
    """Генерировать уникальное имя для интеграции"""
    
    base_names = {
        'bitrix24': 'Bitrix24',
        'amocrm': 'amoCRM',
        '1c': '1C',
        'custom': 'Custom CRM'
    }
    
    base_name = base_names.get(integration_type, integration_type.upper())
    
    # Добавляем домен если есть
    domain = config.api_url
    if domain:
        if domain.startswith('http'):
            from urllib.parse import urlparse
            domain = urlparse(domain).netloc
        
        return f"{base_name} - {domain}"
    
    # Проверяем есть ли уже интеграции этого типа
    existing_count = db.query(Integration).filter(
        and_(
            Integration.tenant_id == tenant_id,
            Integration.type == integration_type
        )
    ).count()
    
    if existing_count > 0:
        return f"{base_name} #{existing_count + 1}"
    
    return base_name


@router.get("/amocrm/oauth/callback")
async def amocrm_oauth_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 - перенаправляет на основной callback
    """
    # Перенаправляем на основной callback в oauth_crm.py
    from fastapi.responses import RedirectResponse
    callback_url = f"/api/v1/amocrm/callback?code={code}&state={state}"
    if referer:
        callback_url += f"&referer={referer}"
    if platform:
        callback_url += f"&platform={platform}"
    
    return RedirectResponse(url=callback_url)


@router.post("/{integration_id}/webhook")
async def handle_custom_webhook(
    integration_id: int,
    request: Request,
    db: Session = Depends(get_db),
):
    """
    Обработка webhook от custom интеграции
    
    Принимает данные в формате JSON с полями:
    - phone: номер телефона
    - email: email
    - name: имя клиента
    - external_id: внешний ID из CRM (опционально)
    """
    # Получаем интеграцию
    integration = db.query(Integration).filter(
        and_(
            Integration.id == integration_id,
            Integration.type == 'custom',
            Integration.is_active == True
        )
    ).first()
    
    if not integration:
        raise HTTPException(status_code=404, detail="Custom интеграция не найдена")
    
    # Получаем данные из webhook
    try:
        data = await request.json()
    except:
        raise HTTPException(status_code=400, detail="Неверный формат данных. Ожидается JSON")
    
    # Извлекаем данные
    phone_raw = data.get('phone')
    email = data.get('email')
    name = data.get('name', 'Клиент')
    external_id = data.get('external_id')
    
    if not phone_raw and not email:
        raise HTTPException(status_code=400, detail="Необходимо указать phone или email")
    
    # Нормализуем телефон
    phone = None
    if phone_raw:
        phone = phone_raw.strip().replace(' ', '').replace('(', '').replace(')', '').replace('-', '')
        if not phone.startswith('+'):
            phone = f"+{phone}"
    
    # Находим или создаем клиента
    customer = None
    
    # Ищем по external_id
    if external_id:
        customer = db.query(Customer).filter(
            and_(
                Customer.tenant_id == integration.tenant_id,
                Customer.meta['external_id'].astext == external_id
            )
        ).first()
    
    # Ищем по телефону
    if not customer and phone:
        customer = db.query(Customer).filter(
            and_(
                Customer.tenant_id == integration.tenant_id,
                Customer.phone == phone
            )
        ).first()
    
    # Ищем по email
    if not customer and email:
        customer = db.query(Customer).filter(
            and_(
                Customer.tenant_id == integration.tenant_id,
                Customer.email == email
            )
        ).first()
    
    # Обновляем или создаем клиента
    if customer:
        # Обновляем существующего
        if phone and customer.phone != phone:
            customer.phone = phone
        if email and customer.email != email:
            customer.email = email
        if customer.meta:
            if external_id:
                customer.meta['external_id'] = external_id
            customer.meta['name'] = name
            customer.meta['source'] = 'custom_webhook'
            customer.meta['last_update'] = datetime.utcnow().isoformat()
        db.commit()
        db.refresh(customer)
    else:
        # Создаем нового
        customer = Customer(
            tenant_id=integration.tenant_id,
            phone=phone,
            email=email,
            tags=['custom_webhook', 'imported'],
            meta={
                'name': name,
                'external_id': external_id,
                'source': 'custom_webhook',
                'created_from': 'webhook',
                'last_update': datetime.utcnow().isoformat()
            }
        )
        db.add(customer)
        db.commit()
        db.refresh(customer)
    
    return {
        "status": "success",
        "message": "Данные клиента обработаны",
        "customer_id": customer.id,
        "phone": customer.phone,
        "email": customer.email
    }

