from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from fastapi import HTTPException, status
from typing import List, Optional, Dict, Any
import re
from datetime import datetime, timedelta

from app.models.content_models import Page, AnalyticsLog
from app.schemas.content_schemas import PageCreate, PageUpdate, AnalyticsLogCreate


# Вспомогательная функция для генерации slug
def generate_slug(title: str) -> str:
    # Преобразуем в нижний регистр
    slug = title.lower()
    # Заменяем пробелы на дефисы
    slug = re.sub(r'\s+', '-', slug)
    # Удаляем все символы, кроме букв, цифр и дефисов
    slug = re.sub(r'[^a-z0-9-]', '', slug)
    # Удаляем повторяющиеся дефисы
    slug = re.sub(r'-+', '-', slug)
    # Удаляем дефисы в начале и конце
    slug = slug.strip('-')
    
    return slug


# Функции для работы со страницами
def get_page(db: Session, page_id: int) -> Optional[Page]:
    return db.query(Page).filter(Page.id == page_id).first()


def get_page_by_slug(db: Session, slug: str) -> Optional[Page]:
    return db.query(Page).filter(Page.slug == slug).first()


def get_pages(
    db: Session, 
    skip: int = 0, 
    limit: int = 100, 
    published_only: bool = True
) -> List[Page]:
    query = db.query(Page)
    
    if published_only:
        query = query.filter(Page.is_published == True)
    
    return query.order_by(Page.title).offset(skip).limit(limit).all()


def create_page(db: Session, page: PageCreate) -> Page:
    # Если slug не предоставлен, генерируем его из заголовка
    if not page.slug:
        page.slug = generate_slug(page.title)
    
    # Проверяем, что страница с таким slug не существует
    if get_page_by_slug(db, page.slug):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Страница с таким slug уже существует"
        )
    
    # Создаем новую страницу
    db_page = Page(
        title=page.title,
        slug=page.slug,
        content=page.content,
        meta_title=page.meta_title,
        meta_description=page.meta_description,
        is_published=page.is_published
    )
    
    try:
        db.add(db_page)
        db.commit()
        db.refresh(db_page)
        return db_page
    except IntegrityError:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Ошибка при создании страницы"
        )


def update_page(db: Session, page_id: int, page: PageUpdate) -> Page:
    db_page = get_page(db, page_id)
    if not db_page:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Страница не найдена"
        )
    
    # Обновляем только предоставленные поля
    update_data = page.dict(exclude_unset=True)
    
    # Если slug изменяется, проверяем его уникальность
    if "slug" in update_data and update_data["slug"] != db_page.slug:
        if get_page_by_slug(db, update_data["slug"]):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Страница с таким slug уже существует"
            )
    
    # Если заголовок изменяется и slug не предоставлен, генерируем новый slug
    if "title" in update_data and "slug" not in update_data:
        update_data["slug"] = generate_slug(update_data["title"])
        # Проверяем уникальность сгенерированного slug
        if get_page_by_slug(db, update_data["slug"]) and get_page_by_slug(db, update_data["slug"]).id != page_id:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Страница с таким slug уже существует"
            )
    
    # Применяем обновления
    for key, value in update_data.items():
        setattr(db_page, key, value)
    
    try:
        db.commit()
        db.refresh(db_page)
        return db_page
    except IntegrityError:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Ошибка при обновлении страницы"
        )


def delete_page(db: Session, page_id: int) -> bool:
    db_page = get_page(db, page_id)
    if not db_page:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Страница не найдена"
        )
    
    try:
        db.delete(db_page)
        db.commit()
        return True
    except Exception:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Ошибка при удалении страницы"
        )


# Функции для работы с аналитикой
def log_analytics_event(db: Session, log: AnalyticsLogCreate) -> AnalyticsLog:
    # Создаем новую запись аналитики
    db_log = AnalyticsLog(
        user_id=log.user_id,
        event_type=log.event_type,
        page_url=log.page_url,
        product_id=log.product_id,
        category_id=log.category_id,
        ip_address=log.ip_address,
        user_agent=log.user_agent,
        referrer=log.referrer,
        additional_data=log.additional_data
    )
    
    try:
        db.add(db_log)
        db.commit()
        db.refresh(db_log)
        return db_log
    except IntegrityError:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Ошибка при логировании события"
        )


def get_analytics_logs(
    db: Session, 
    skip: int = 0, 
    limit: int = 100, 
    event_type: Optional[str] = None,
    user_id: Optional[int] = None,
    product_id: Optional[int] = None,
    category_id: Optional[int] = None,
    start_date: Optional[datetime] = None,
    end_date: Optional[datetime] = None
) -> List[AnalyticsLog]:
    query = db.query(AnalyticsLog)
    
    # Применяем фильтры
    if event_type:
        query = query.filter(AnalyticsLog.event_type == event_type)
    
    if user_id:
        query = query.filter(AnalyticsLog.user_id == user_id)
    
    if product_id:
        query = query.filter(AnalyticsLog.product_id == product_id)
    
    if category_id:
        query = query.filter(AnalyticsLog.category_id == category_id)
    
    if start_date:
        query = query.filter(AnalyticsLog.created_at >= start_date)
    
    if end_date:
        query = query.filter(AnalyticsLog.created_at <= end_date)
    
    return query.order_by(AnalyticsLog.created_at.desc()).offset(skip).limit(limit).all()


def get_analytics_report(
    db: Session, 
    period: str = "day",
    start_date: Optional[datetime] = None,
    end_date: Optional[datetime] = None
) -> Dict[str, Any]:
    # Устанавливаем период по умолчанию, если не указан
    if not start_date:
        if period == "day":
            start_date = datetime.utcnow() - timedelta(days=1)
        elif period == "week":
            start_date = datetime.utcnow() - timedelta(weeks=1)
        elif period == "month":
            start_date = datetime.utcnow() - timedelta(days=30)
        elif period == "year":
            start_date = datetime.utcnow() - timedelta(days=365)
        else:
            start_date = datetime.utcnow() - timedelta(days=30)  # По умолчанию 30 дней
    
    if not end_date:
        end_date = datetime.utcnow()
    
    # Получаем все события за указанный период
    logs = db.query(AnalyticsLog).filter(
        AnalyticsLog.created_at >= start_date,
        AnalyticsLog.created_at <= end_date
    ).all()
    
    # Подсчитываем статистику
    total_visits = len(logs)
    unique_visitors = len(set([log.ip_address for log in logs if log.ip_address]))
    
    # Подсчитываем просмотры страниц
    page_views = {}
    for log in logs:
        if log.event_type == "page_view" and log.page_url:
            page_views[log.page_url] = page_views.get(log.page_url, 0) + 1
    
    # Подсчитываем просмотры продуктов
    product_views = {}
    for log in logs:
        if log.event_type == "product_view" and log.product_id:
            product_id = str(log.product_id)
            product_views[product_id] = product_views.get(product_id, 0) + 1
    
    # Подсчитываем добавления в корзину
    cart_additions = sum(1 for log in logs if log.event_type == "add_to_cart")
    
    # Подсчитываем заказы и выручку
    orders_count = sum(1 for log in logs if log.event_type == "order_created")
    
    # Для расчета выручки и среднего чека нам нужны данные о заказах
    # В данном примере мы просто используем заглушки
    revenue = 0
    average_order_value = 0
    
    # Формируем отчет
    report = {
        "period": period,
        "start_date": start_date,
        "end_date": end_date,
        "total_visits": total_visits,
        "unique_visitors": unique_visitors,
        "page_views": page_views,
        "product_views": product_views,
        "cart_additions": cart_additions,
        "orders_count": orders_count,
        "revenue": revenue,
        "average_order_value": average_order_value
    }
    
    return report 