"""
Webhook обработчики для событий из CRM систем
"""
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.orm import Session
from sqlalchemy import and_
from typing import Dict, Any
from datetime import datetime, timedelta
from pydantic import BaseModel

from app.db.session import get_db
from app.db.models import (
    User, Customer, Integration, UserIndustryTemplate, 
    IndustryTemplate, ScheduledNotification, CustomField, TenantSettings
)
from app.utils.encryption import decrypt_token
import requests
import logging

router = APIRouter(prefix="/crm-webhooks", tags=["crm-webhooks"])
logger = logging.getLogger(__name__)


# Schemas
class Bitrix24WebhookData(BaseModel):
    """Данные webhook от Bitrix24"""
    event: str
    data: Dict[str, Any]
    auth: Dict[str, Any] | None = None


def get_clinic_address(db: Session, tenant_id: int, integration: Integration | None = None) -> str:
    """Получить адрес клиники из настроек или CRM"""
    
    # 1. Пробуем получить из CustomField (поиск по name или label)
    clinic_field = db.query(CustomField).filter(
        and_(
            CustomField.tenant_id == tenant_id,
            (CustomField.name == 'clinic_address') | (CustomField.label.ilike('%адрес%клиник%'))
        )
    ).first()
    
    # CustomField не хранит значение напрямую, это поле для формы
    # Значения хранятся в Customer.meta или других местах
    # Пока пропускаем этот вариант
    
    # 2. Пробуем получить из TenantSettings (если есть поле settings)
    tenant_settings = db.query(TenantSettings).filter(
        TenantSettings.tenant_id == tenant_id
    ).first()
    
    # 3. Пробуем получить из CRM через API
    if integration and integration.type == 'bitrix24':
        try:
            config = integration.config or {}
            access_token_enc = config.get("access_token_enc")
            api_url = config.get("api_url") or config.get("domain")
            
            if access_token_enc and api_url:
                access_token = decrypt_token(access_token_enc)
                # Получаем информацию о компании из Bitrix24
                address = get_bitrix24_company_address(api_url, access_token)
                if address:
                    return address
        except Exception:
            logger.warning("Failed to fetch clinic address from Bitrix24", exc_info=True)
    
    # 4. Возвращаем значение по умолчанию
    return "Адрес не указан"


def get_doctor_name(db: Session, tenant_id: int, integration: Integration | None = None, appointment_id: str | None = None) -> str:
    """Получить имя доктора из настроек или CRM"""
    
    # 1. Пробуем получить из CustomField (поиск по name или label)
    doctor_field = db.query(CustomField).filter(
        and_(
            CustomField.tenant_id == tenant_id,
            (CustomField.name == 'doctor_name') | (CustomField.label.ilike('%доктор%') | CustomField.label.ilike('%врач%'))
        )
    ).first()
    
    # CustomField не хранит значение напрямую, это поле для формы
    # Значения хранятся в Customer.meta или других местах
    # Пока пропускаем этот вариант
    
    # 2. Пробуем получить из CRM через API (если передан appointment_id)
    if integration and appointment_id:
        try:
            config = integration.config or {}
            access_token_enc = config.get("access_token_enc")
            api_url = config.get("api_url") or config.get("domain")
            
            if access_token_enc and api_url:
                access_token = decrypt_token(access_token_enc)
                # Получаем информацию о докторе из сделки/лида в Bitrix24
                doctor_name = get_bitrix24_doctor_name(api_url, access_token, appointment_id)
                if doctor_name:
                    return doctor_name
        except Exception:
            logger.warning("Failed to fetch doctor name from Bitrix24", exc_info=True)
    
    # 3. Возвращаем значение по умолчанию
    return "Доктор"


def get_bitrix24_company_address(api_url: str, access_token: str) -> str | None:
    """Получить адрес компании из Bitrix24 (синхронная версия)"""
    try:
        rest_url = f"{api_url.rstrip('/')}/rest/crm.company.list.json"
        from app.utils.http import http_get
        response = http_get(
            rest_url,
            params={"auth": access_token, "filter[ACTIVE]": "Y", "select[]": ["ADDRESS", "TITLE"]},
            timeout=10.0,
        )
        
        if response.status_code == 200:
            data = response.json()
            if data.get("result") and len(data["result"]) > 0:
                company = data["result"][0]
                return company.get("ADDRESS") or company.get("TITLE")
        
        return None
    except Exception:
        logger.warning("Failed to get Bitrix24 company address", exc_info=True)
        return None


def get_bitrix24_doctor_name(api_url: str, access_token: str, deal_id: str) -> str | None:
    """Получить имя доктора из сделки в Bitrix24 (синхронная версия)"""
    try:
        rest_url = f"{api_url.rstrip('/')}/rest/crm.deal.get.json"
        
        response = requests.get(
            rest_url,
            params={
                "auth": access_token,
                "id": deal_id
            },
            timeout=10.0
        )
        
        if response.status_code == 200:
            data = response.json()
            if data.get("result"):
                deal = data["result"]
                # Пробуем получить из кастомных полей
                # Обычно это UF_CRM_DOCTOR_NAME или подобное поле
                for key, value in deal.items():
                    if 'DOCTOR' in key.upper() or 'ВРАЧ' in str(value).upper():
                        if value:
                            return str(value)
        
        return None
    except Exception:
        return None


def parse_bitrix_date(date_str: str) -> datetime:
    """Парсинг даты из Bitrix24"""
    try:
        # Bitrix24 format: "2024-10-15T14:00:00+03:00"
        return datetime.fromisoformat(date_str.replace('+03:00', ''))
    except:
        return datetime.utcnow()


def get_or_create_customer(
    db: Session,
    tenant_id: int,
    phone: str | None = None,
    email: str | None = None,
    name: str | None = None,
    tg_chat_id: str | None = None,
    external_id: str | None = None
) -> Customer:
    """Найти или создать клиента"""
    
    # Ищем по external_id
    if external_id:
        customer = db.query(Customer).filter(
            and_(
                Customer.tenant_id == tenant_id,
                Customer.meta['crm_lead_id'].astext == external_id
            )
        ).first()
        if customer:
            return customer
    
    # Ищем по телефону
    if phone:
        customer = db.query(Customer).filter(
            and_(
                Customer.tenant_id == tenant_id,
                Customer.phone == phone
            )
        ).first()
        if customer:
            # Обновляем данные
            if email:
                customer.email = email
            if name and customer.meta:
                customer.meta['name'] = name
            if external_id and customer.meta:
                customer.meta['crm_lead_id'] = external_id
            db.commit()
            return customer
    
    # Создаём нового
    customer = Customer(
        tenant_id=tenant_id,
        phone=phone,
        email=email,
        tg_chat_id=tg_chat_id,
        meta={
            'name': name,
            'crm_lead_id': external_id
        }
    )
    db.add(customer)
    db.commit()
    db.refresh(customer)
    
    return customer


@router.post("/bitrix24/lead-created")
async def handle_bitrix_lead_created(
    request: Request,
    db: Session = Depends(get_db),
):
    """
    Обработка создания лида в Bitrix24
    
    Ожидаемые поля:
    - PHONE: телефон
    - EMAIL: email  
    - NAME: имя
    - UF_CRM_APPOINTMENT_DATE: дата приёма
    - UF_CRM_APPOINTMENT_TIME: время приёма
    """
    
    # Получаем данные из webhook
    form_data = await request.form()
    data = dict(form_data)
    
    # Извлекаем данные
    lead_id = data.get('data[FIELDS][ID]')
    phone_raw = data.get('data[FIELDS][PHONE][0][VALUE]')
    email = data.get('data[FIELDS][EMAIL][0][VALUE]')
    name = data.get('data[FIELDS][NAME]') or data.get('data[FIELDS][TITLE]')
    
    # Дата и время приёма (кастомные поля)
    appointment_date_str = data.get('data[FIELDS][UF_CRM_APPOINTMENT_DATE]')
    appointment_time_str = data.get('data[FIELDS][UF_CRM_APPOINTMENT_TIME]') or "14:00"
    
    if not phone_raw:
        return {"status": "error", "message": "Телефон не указан"}
    
    # Нормализуем телефон
    phone = phone_raw.strip().replace(' ', '').replace('(', '').replace(')', '').replace('-', '')
    if not phone.startswith('+'):
        phone = f"+{phone}"
    
    # Парсим дату приёма
    if appointment_date_str:
        try:
            # Формат Bitrix24: "15.10.2024"
            day, month, year = appointment_date_str.split('.')
            hour, minute = appointment_time_str.split(':')
            appointment_datetime = datetime(
                int(year), int(month), int(day), 
                int(hour), int(minute)
            )
        except:
            appointment_datetime = None
    else:
        appointment_datetime = None
    
    # Находим интеграцию Bitrix24 (берём первую активную)
    integration = db.query(Integration).filter(
        and_(
            Integration.type == 'bitrix24',
            Integration.status == 'connected',
            Integration.is_active == True
        )
    ).first()
    
    if not integration:
        return {"status": "error", "message": "Активная интеграция Bitrix24 не найдена"}
    
    tenant_id = integration.tenant_id
    
    # Создаём или находим клиента
    customer = get_or_create_customer(
        db=db,
        tenant_id=tenant_id,
        phone=phone,
        email=email,
        name=name,
        external_id=lead_id
    )
    
    # Находим активные шаблоны для триггера "appointment.created"
    user_templates = db.query(UserIndustryTemplate).join(
        IndustryTemplate
    ).filter(
        and_(
            UserIndustryTemplate.tenant_id == tenant_id,
            UserIndustryTemplate.is_active == True,
            IndustryTemplate.trigger_type == 'appointment.created'
        )
    ).all()
    
    scheduled_count = 0
    
    for user_template in user_templates:
        industry_template = db.query(IndustryTemplate).filter(
            IndustryTemplate.id == user_template.industry_template_id
        ).first()
        
        if not industry_template:
            continue
        
        # Определяем когда отправить
        if appointment_datetime:
            send_time = appointment_datetime - timedelta(hours=industry_template.delay_hours)
        else:
            send_time = datetime.utcnow()
        
        # Получаем данные из настроек/CRM
        clinic_address = get_clinic_address(db, tenant_id, integration)
        doctor_name = get_doctor_name(db, tenant_id, integration, lead_id)
        
        # Подготавливаем payload
        payload = {
            'customer_name': name or 'Клиент',
            'appointment_date': appointment_datetime.strftime('%d %B') if appointment_datetime else '',
            'appointment_time': appointment_datetime.strftime('%H:%M') if appointment_datetime else '',
            'clinic_address': clinic_address,
            'doctor_name': doctor_name,
        }
        
        # Создаём запланированное уведомление
        scheduled = ScheduledNotification(
            tenant_id=tenant_id,
            customer_id=customer.id,
            template_id=user_template.template_id,
            user_template_id=user_template.id,
            scheduled_at=send_time,
            payload=payload,
            channels=user_template.channels or industry_template.channels,
            trigger_type='appointment.created',
            external_id=lead_id
        )
        db.add(scheduled)
        scheduled_count += 1
    
    db.commit()
    
    return {
        "status": "success",
        "message": f"Обработан лид {lead_id}",
        "customer_id": customer.id,
        "scheduled_notifications": scheduled_count
    }


@router.post("/bitrix24/appointment-soon")
async def handle_appointment_reminder(
    request: Request,
    db: Session = Depends(get_db),
):
    """
    Триггер для напоминаний о приёме
    Запускается за N часов до приёма
    """
    
    form_data = await request.form()
    data = dict(form_data)
    
    appointment_id = data.get('data[FIELDS][ID]')
    customer_id = data.get('data[FIELDS][CONTACT_ID]')
    appointment_date = data.get('data[FIELDS][UF_CRM_APPOINTMENT_DATE]')
    
    # Реализуем логику напоминаний о приёмах
    # Находим интеграцию Bitrix24
    integration = db.query(Integration).filter(
        and_(
            Integration.type == 'bitrix24',
            Integration.status == 'connected',
            Integration.is_active == True
        )
    ).first()
    
    if not integration:
        return {"status": "error", "message": "Активная интеграция Bitrix24 не найдена"}
    
    tenant_id = integration.tenant_id
    
    # Парсим дату приёма
    appointment_datetime = None
    if appointment_date:
        try:
            # Формат Bitrix24 может быть разным
            if 'T' in appointment_date:
                appointment_datetime = datetime.fromisoformat(appointment_date.replace('+03:00', ''))
            else:
                # Формат "15.10.2024"
                day, month, year = appointment_date.split('.')
                appointment_datetime = datetime(int(year), int(month), int(day))
        except:
            appointment_datetime = None
    
    if not appointment_datetime:
        return {"status": "error", "message": "Не удалось распарсить дату приёма"}
    
    # Находим клиента
    customer = None
    if customer_id:
        customer = db.query(Customer).filter(
            and_(
                Customer.tenant_id == tenant_id,
                Customer.meta['crm_lead_id'].astext == str(customer_id)
            )
        ).first()
    
    if not customer:
        return {"status": "error", "message": "Клиент не найден"}
    
    # Находим шаблоны для напоминаний (appointment.soon)
    user_templates = db.query(UserIndustryTemplate).join(
        IndustryTemplate
    ).filter(
        and_(
            UserIndustryTemplate.tenant_id == tenant_id,
            UserIndustryTemplate.is_active == True,
            IndustryTemplate.trigger_type == 'appointment.soon'
        )
    ).all()
    
    scheduled_count = 0
    
    for user_template in user_templates:
        industry_template = db.query(IndustryTemplate).filter(
            IndustryTemplate.id == user_template.industry_template_id
        ).first()
        
        if not industry_template:
            continue
        
        # Определяем время отправки напоминания (за N часов до приёма)
        # delay_hours определяет за сколько часов до приёма отправлять
        reminder_hours = industry_template.delay_hours or 24  # По умолчанию за 24 часа
        send_time = appointment_datetime - timedelta(hours=reminder_hours)
        
        # Не отправляем напоминания в прошлое
        if send_time < datetime.utcnow():
            continue
        
        # Получаем данные из настроек/CRM
        clinic_address = get_clinic_address(db, tenant_id, integration)
        doctor_name = get_doctor_name(db, tenant_id, integration, appointment_id)
        
        # Подготавливаем payload
        payload = {
            'customer_name': customer.meta.get('name', 'Клиент') if customer.meta else 'Клиент',
            'appointment_date': appointment_datetime.strftime('%d %B'),
            'appointment_time': appointment_datetime.strftime('%H:%M'),
            'clinic_address': clinic_address,
            'doctor_name': doctor_name,
        }
        
        # Создаём запланированное уведомление
        scheduled = ScheduledNotification(
            tenant_id=tenant_id,
            customer_id=customer.id,
            template_id=user_template.template_id,
            user_template_id=user_template.id,
            scheduled_at=send_time,
            payload=payload,
            channels=user_template.channels or industry_template.channels,
            trigger_type='appointment.soon',
            external_id=str(appointment_id)
        )
        db.add(scheduled)
        scheduled_count += 1
    
    db.commit()
    
    return {
        "status": "success",
        "message": f"Создано {scheduled_count} напоминаний о приёме",
        "scheduled_notifications": scheduled_count
    }


@router.post("/bitrix24/appointment-completed")
async def handle_appointment_completed(
    request: Request,
    db: Session = Depends(get_db),
):
    """
    Триггер когда приём завершён
    Отправляет благодарность
    """
    
    form_data = await request.form()
    data = dict(form_data)
    
    appointment_id = data.get('data[FIELDS][ID]')
    lead_id = data.get('data[FIELDS][LEAD_ID]')
    
    # Находим клиента по lead_id
    customer = db.query(Customer).filter(
        Customer.meta['crm_lead_id'].astext == lead_id
    ).first()
    
    if not customer:
        return {"status": "error", "message": "Клиент не найден"}
    
    # Находим шаблоны для "appointment.completed"
    user_templates = db.query(UserIndustryTemplate).join(
        IndustryTemplate
    ).filter(
        and_(
            UserIndustryTemplate.tenant_id == customer.tenant_id,
            UserIndustryTemplate.is_active == True,
            IndustryTemplate.trigger_type == 'appointment.completed'
        )
    ).all()
    
    for user_template in user_templates:
        industry_template = db.query(IndustryTemplate).filter(
            IndustryTemplate.id == user_template.industry_template_id
        ).first()
        
        send_time = datetime.utcnow() + timedelta(hours=industry_template.delay_hours)
        
        payload = {
            'customer_name': customer.meta.get('name', 'Клиент'),
            'feedback_link': 'https://feedback.example.com'
        }
        
        scheduled = ScheduledNotification(
            tenant_id=customer.tenant_id,
            customer_id=customer.id,
            template_id=user_template.template_id,
            user_template_id=user_template.id,
            scheduled_at=send_time,
            payload=payload,
            channels=user_template.channels,
            trigger_type='appointment.completed',
            external_id=appointment_id
        )
        db.add(scheduled)
    
    db.commit()
    
    return {"status": "success"}


@router.get("/health")
def health_check():
    """Проверка работоспособности webhook endpoint"""
    return {"status": "ok", "service": "crm-webhooks"}





















