"""
Celery tasks для синхронизации данных с CRM системами
"""
from celery import shared_task
from sqlalchemy.orm import Session
from datetime import datetime
import asyncio

from app.db.session import SessionLocal
from app.db.models import Integration, IntegrationSyncLog, Customer
from app.services.crm_integrations import get_crm_client


@shared_task(bind=True, name="app.workers.crm_sync.sync_crm_customers")
def sync_crm_customers(self, integration_id: int, sync_log_id: int, tenant_id: int):
    """
    Синхронизация клиентов из CRM системы
    """
    db: Session = SessionLocal()
    
    try:
        # Получаем интеграцию
        integration = db.query(Integration).filter(Integration.id == integration_id).first()
        if not integration:
            raise Exception(f"Integration {integration_id} not found")
        
        # Получаем лог синхронизации
        sync_log = db.query(IntegrationSyncLog).filter(IntegrationSyncLog.id == sync_log_id).first()
        if not sync_log:
            raise Exception(f"Sync log {sync_log_id} not found")
        
        # Создаем CRM клиент
        try:
            crm_client = get_crm_client(integration.type, integration.config)
        except ValueError as e:
            if "не авторизована" in str(e):
                raise Exception("Интеграция не авторизована. Сначала завершите процесс авторизации.")
            raise
        
        # Запускаем синхронизацию
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        
        try:
            result = loop.run_until_complete(
                _sync_customers_async(crm_client, integration, sync_log, tenant_id, db)
            )
        finally:
            loop.run_until_complete(crm_client.close())
            loop.close()
        
        return result
        
    except Exception as e:
        # Обновляем лог с ошибкой
        sync_log = db.query(IntegrationSyncLog).filter(IntegrationSyncLog.id == sync_log_id).first()
        if sync_log:
            sync_log.status = 'failed'
            sync_log.error_message = str(e)
            sync_log.completed_at = datetime.utcnow()
            db.commit()
        
        # Обновляем статус интеграции
        integration = db.query(Integration).filter(Integration.id == integration_id).first()
        if integration:
            integration.status = 'error'
            integration.last_error = str(e)
            db.commit()
        
        raise
    finally:
        db.close()


async def _sync_customers_async(crm_client, integration, sync_log, tenant_id, db):
    """
    Асинхронная синхронизация клиентов
    """
    records_processed = 0
    records_created = 0
    records_updated = 0
    records_failed = 0
    
    batch_size = 100
    offset = 0
    
    try:
        while True:
            # Получаем контакты из CRM
            contacts = await crm_client.get_contacts(limit=batch_size, offset=offset)
            
            if not contacts:
                break
            
            for crm_contact in contacts:
                records_processed += 1
                
                try:
                    # Нормализуем контакт
                    normalized = crm_client.normalize_contact(crm_contact)
                    
                    # Ищем существующего клиента по CRM ID
                    crm_id = crm_contact.get('id')
                    existing_customer = None
                    
                    if crm_id:
                        existing_customer = db.query(Customer).filter(
                            Customer.tenant_id == tenant_id,
                            Customer.meta['crm_id'].astext == crm_id
                        ).first()
                    
                    # Если нет по CRM ID, пробуем найти по email
                    if not existing_customer and normalized.get('email'):
                        existing_customer = db.query(Customer).filter(
                            Customer.tenant_id == tenant_id,
                            Customer.email == normalized['email']
                        ).first()
                    
                    if existing_customer:
                        # Обновляем существующего клиента
                        if normalized.get('phone'):
                            existing_customer.phone = normalized['phone']
                        if normalized.get('tags'):
                            # Объединяем теги
                            existing_tags = set(existing_customer.tags or [])
                            new_tags = set(normalized['tags'])
                            existing_customer.tags = list(existing_tags.union(new_tags))
                        
                        # Обновляем метаданные
                        existing_meta = existing_customer.meta or {}
                        existing_meta.update(normalized.get('meta', {}))
                        existing_customer.meta = existing_meta
                        
                        records_updated += 1
                    else:
                        # Создаем нового клиента
                        new_customer = Customer(
                            tenant_id=tenant_id,
                            email=normalized.get('email'),
                            phone=normalized.get('phone'),
                            tags=normalized.get('tags', []),
                            meta=normalized.get('meta', {})
                        )
                        db.add(new_customer)
                        records_created += 1
                    
                    # Коммитим каждые 10 записей
                    if records_processed % 10 == 0:
                        db.commit()
                        
                        # Обновляем прогресс в логе
                        sync_log.records_processed = records_processed
                        sync_log.records_created = records_created
                        sync_log.records_updated = records_updated
                        sync_log.records_failed = records_failed
                        db.commit()
                
                except Exception as e:
                    records_failed += 1
                    print(f"Error syncing contact {crm_contact.get('id')}: {e}")
                    continue
            
            # Переходим к следующей порции
            offset += batch_size
            
            # Если получили меньше записей, чем запрашивали - это последняя порция
            if len(contacts) < batch_size:
                break
        
        # Финальный коммит
        db.commit()
        
        # Обновляем лог синхронизации
        sync_log.status = 'success'
        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()
        db.commit()
        
        # Обновляем интеграцию
        integration.status = 'connected'
        integration.last_sync_at = datetime.utcnow()
        integration.last_error = None
        integration.sync_stats = {
            'customers_synced': records_created + records_updated,
            'last_sync_records': records_processed,
            'total_created': records_created,
            'total_updated': records_updated,
            'total_failed': records_failed
        }
        db.commit()
        
        return {
            'status': 'success',
            'records_processed': records_processed,
            'records_created': records_created,
            'records_updated': records_updated,
            'records_failed': records_failed
        }
        
    except Exception as e:
        # Обновляем лог с ошибкой
        sync_log.status = 'failed'
        sync_log.error_message = str(e)
        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()
        db.commit()
        
        # Обновляем интеграцию
        integration.status = 'error'
        integration.last_error = str(e)
        db.commit()
        
        raise


@shared_task(bind=True, name="app.workers.crm_sync.test_crm_connection")
def test_crm_connection(self, integration_id: int):
    """
    Тестирование подключения к CRM
    """
    db: Session = SessionLocal()
    
    try:
        # Получаем интеграцию
        integration = db.query(Integration).filter(Integration.id == integration_id).first()
        if not integration:
            raise Exception(f"Integration {integration_id} not found")
        
        # Создаем CRM клиент
        try:
            crm_client = get_crm_client(integration.type, integration.config)
        except ValueError as e:
            if "не авторизована" in str(e):
                raise Exception("Интеграция не авторизована. Сначала завершите процесс авторизации.")
            raise
        
        # Тестируем подключение
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        
        try:
            is_connected = loop.run_until_complete(crm_client.test_connection())
        finally:
            loop.run_until_complete(crm_client.close())
            loop.close()
        
        if is_connected:
            integration.status = 'connected'
            integration.last_error = None
            db.commit()
            return {'status': 'connected', 'message': 'Connection successful'}
        else:
            integration.status = 'error'
            integration.last_error = 'Connection test failed'
            db.commit()
            return {'status': 'error', 'message': 'Connection test failed'}
    
    except Exception as e:
        integration = db.query(Integration).filter(Integration.id == integration_id).first()
        if integration:
            integration.status = 'error'
            integration.last_error = str(e)
            db.commit()
        
        return {'status': 'error', 'message': str(e)}
    finally:
        db.close()


@shared_task(bind=True, name="app.workers.crm_sync.scheduled_sync_all")
def scheduled_sync_all(self):
    """
    Запланированная синхронизация всех активных интеграций
    Можно добавить в celery beat для автоматической синхронизации
    """
    db: Session = SessionLocal()
    
    try:
        # Получаем все активные интеграции
        integrations = db.query(Integration).filter(
            Integration.is_active == True,
            Integration.status == 'connected'
        ).all()
        
        results = []
        
        for integration in integrations:
            # Создаем лог синхронизации
            sync_log = IntegrationSyncLog(
                integration_id=integration.id,
                sync_type='customers',
                status='in_progress',
                started_at=datetime.utcnow()
            )
            db.add(sync_log)
            db.commit()
            db.refresh(sync_log)
            
            # Запускаем синхронизацию в фоне
            result = sync_crm_customers.delay(
                integration.id,
                sync_log.id,
                integration.tenant_id
            )
            
            results.append({
                'integration_id': integration.id,
                'integration_name': integration.name,
                'task_id': result.id
            })
        
        return {
            'message': f'Запущена синхронизация {len(integrations)} интеграций',
            'results': results
        }
    
    finally:
        db.close()

