from datetime import date, datetime, timedelta
from typing import Dict, List, Optional, Any

from fastapi import Depends, FastAPI, HTTPException, Query
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from sqlalchemy import and_, desc, select, func
from sqlalchemy.ext.asyncio import AsyncSession

from services.calendar_service.models import CalendarEntry, CycleData, HealthInsights
import services.calendar_service.schemas as schemas
from services.calendar_service.schemas import (CalendarEntryCreate, CalendarEntryResponse, 
                                               CycleDataResponse, CycleOverview, EntryType, 
                                               FlowIntensity, HealthInsightResponse, MoodType,
                                               CalendarEventCreate)
from services.calendar_service.mobile_endpoint import MobileCalendarEntryCreate, mobile_create_calendar_entry
from services.calendar_service.mobile_responses import (MobileCalendarEntryResponse, 
                                                        MobileCalendarPeriodInfo, 
                                                        MobilePredictionInfo,
                                                        MobileCalendarResponse)
from shared.auth import get_current_user_from_token as get_current_user
from shared.config import settings
from shared.database import get_db

app = FastAPI(title="Calendar Service", version="1.0.0")

# CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.CORS_ORIGINS,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.get("/health")
async def health_check():
    """Health check endpoint"""
    return {"status": "healthy", "service": "calendar_service"}

@app.get("/api/v1/events")
async def get_events_public(db: AsyncSession = Depends(get_db)):
    """Get calendar events (public endpoint for testing)"""
    result = await db.execute(
        select(CalendarEntry)
        .order_by(CalendarEntry.created_at.desc())
        .limit(50)
    )
    entries = result.scalars().all()
    return [schemas.CalendarEntryResponse.model_validate(entry) for entry in entries] if entries else []

@app.get("/debug/entries")
async def debug_entries(db: AsyncSession = Depends(get_db)):
    """Debug endpoint for entries without auth"""
    # Получить последние 10 записей из БД для отладки
    query = select(CalendarEntry).limit(10)
    result = await db.execute(query)
    entries = result.scalars().all()
    
    # Преобразовать в словари для ответа
    entries_list = []
    for entry in entries:
        entry_dict = {
            "id": entry.id,
            "user_id": entry.user_id,
            "entry_date": str(entry.entry_date),
            "entry_type": entry.entry_type,
            "note": entry.notes,
            "symptoms": entry.symptoms,
            "flow_intensity": entry.flow_intensity,
            "mood": entry.mood,
            "created_at": str(entry.created_at)
        }
        entries_list.append(entry_dict)
    
    return entries_list

@app.get("/debug/add-entry")
async def debug_add_entry(db: AsyncSession = Depends(get_db)):
    """Debug endpoint to add a test entry without auth"""
    try:
        # Создаем тестовую запись
        new_entry = CalendarEntry(
            user_id=29,  # ID пользователя
            entry_date=date.today(),
            entry_type="period",
            flow_intensity="medium",
            period_symptoms=["cramps", "headache"],
            mood="neutral",
            symptoms=["headache", "cramps"],
            notes="Test entry added via debug endpoint",
            is_predicted=False
        )
        
        db.add(new_entry)
        await db.commit()
        await db.refresh(new_entry)
        
        return {
            "message": "Test entry added successfully",
            "entry_id": new_entry.id,
            "user_id": new_entry.user_id,
            "entry_date": str(new_entry.entry_date),
            "entry_type": new_entry.entry_type
        }
    except Exception as e:
        await db.rollback()
        return {"error": str(e)}


# Используем классы из schemas


def calculate_cycle_phase(
    cycle_start: date, cycle_length: int, current_date: date
) -> str:
    """Calculate current cycle phase"""
    days_since_start = (current_date - cycle_start).days

    if days_since_start <= 5:
        return "menstrual"
    elif days_since_start <= cycle_length // 2 - 2:
        return "follicular"
    elif cycle_length // 2 - 2 < days_since_start <= cycle_length // 2 + 2:
        return "ovulation"
    else:
        return "luteal"


async def calculate_predictions(user_id: int, db: AsyncSession):
    """Calculate cycle predictions based on historical data"""
    # Get last 6 cycles for calculations
    cycles = await db.execute(
        select(CycleData)
        .filter(CycleData.user_id == user_id)
        .order_by(desc(CycleData.cycle_start_date))
        .limit(6)
    )
    cycle_list = cycles.scalars().all()

    if len(cycle_list) < 2:
        return None

    # Calculate averages
    cycle_lengths = [c.cycle_length for c in cycle_list if c.cycle_length]
    period_lengths = [c.period_length for c in cycle_list if c.period_length]

    if not cycle_lengths:
        return None

    avg_cycle = sum(cycle_lengths) / len(cycle_lengths)
    avg_period = sum(period_lengths) / len(period_lengths) if period_lengths else 5

    # Predict next period
    last_cycle = cycle_list[0]
    next_period_date = last_cycle.cycle_start_date + timedelta(days=int(avg_cycle))

    return {
        "avg_cycle_length": int(avg_cycle),
        "avg_period_length": int(avg_period),
        "next_period_predicted": next_period_date,
        "ovulation_date": last_cycle.cycle_start_date
        + timedelta(days=int(avg_cycle // 2)),
    }


@app.post("/api/v1/entries", response_model=CalendarEntryResponse, status_code=201)
@app.post("/api/v1/entry", response_model=CalendarEntryResponse, status_code=201)
async def create_calendar_entry_legacy(
    entry_data: CalendarEntryCreate,
    current_user: Dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Create a new calendar entry via legacy endpoint"""
    return await create_calendar_entry(entry_data, current_user, db)


@app.post("/api/v1/calendar/entry", response_model=CalendarEntryResponse, status_code=201)
async def create_calendar_entry_mobile_app(
    entry_data: CalendarEventCreate,
    current_user: Dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Create a new calendar entry via mobile app format endpoint"""
    # Convert mobile app format to server format
    server_entry_data = entry_data.to_server_format()
    response = await create_calendar_entry(server_entry_data, current_user, db)
    return response


async def update_cycle_data(user_id: int, period_date: date, db: AsyncSession):
    """Update cycle data when period is logged"""

    # Get last cycle
    last_cycle = await db.execute(
        select(CycleData)
        .filter(CycleData.user_id == user_id)
        .order_by(desc(CycleData.cycle_start_date))
        .limit(1)
    )
    last_cycle_data = last_cycle.scalars().first()

    if last_cycle_data:
        # Calculate cycle length
        cycle_length = (period_date - last_cycle_data.cycle_start_date).days
        last_cycle_data.cycle_length = cycle_length

    # Create new cycle
    predictions = await calculate_predictions(user_id, db)

    new_cycle = CycleData(
        user_id=user_id,
        cycle_start_date=period_date,
        avg_cycle_length=predictions["avg_cycle_length"] if predictions else None,
        next_period_predicted=predictions["next_period_predicted"]
        if predictions
        else None,
        ovulation_date=predictions["ovulation_date"] if predictions else None,
    )

    db.add(new_cycle)
    await db.commit()


@app.get("/api/v1/entries", response_model=List[CalendarEntryResponse])
async def get_calendar_entries(
    current_user: Dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    start_date: Optional[date] = Query(None),
    end_date: Optional[date] = Query(None),
    entry_type: Optional[EntryType] = Query(None),
    limit: int = Query(100, ge=1, le=365),
):
    """Get calendar entries with optional filtering"""

    query = select(CalendarEntry).filter(CalendarEntry.user_id == current_user["user_id"])

    if start_date:
        query = query.filter(CalendarEntry.entry_date >= start_date)
    if end_date:
        query = query.filter(CalendarEntry.entry_date <= end_date)
    if entry_type:
        query = query.filter(CalendarEntry.entry_type == entry_type.value)

    query = query.order_by(desc(CalendarEntry.entry_date)).limit(limit)

    result = await db.execute(query)
    entries = result.scalars().all()

    return [CalendarEntryResponse.model_validate(entry) for entry in entries]


@app.get("/api/v1/cycle-overview", response_model=CycleOverview)
async def get_cycle_overview(
    current_user: Dict = Depends(get_current_user), db: AsyncSession = Depends(get_db)
):
    """Get current cycle overview and predictions"""

    # Get current cycle
    current_cycle = await db.execute(
        select(CycleData)
        .filter(CycleData.user_id == current_user["user_id"])
        .order_by(desc(CycleData.cycle_start_date))
        .limit(1)
    )
    cycle_data = current_cycle.scalars().first()

    if not cycle_data:
        return CycleOverview(
            current_cycle_day=None,
            current_phase="unknown",
            next_period_date=None,
            days_until_period=None,
            cycle_regularity="unknown",
            avg_cycle_length=None,
        )

    today = date.today()
    current_cycle_day = (today - cycle_data.cycle_start_date).days + 1

    # Calculate current phase
    cycle_length = cycle_data.avg_cycle_length or 28
    current_phase = calculate_cycle_phase(
        cycle_data.cycle_start_date, cycle_length, today
    )

    # Days until next period
    next_period_date = cycle_data.next_period_predicted
    days_until_period = None
    if next_period_date:
        days_until_period = (next_period_date - today).days

    # Calculate regularity
    cycles = await db.execute(
        select(CycleData)
        .filter(CycleData.user_id == current_user["user_id"])
        .order_by(desc(CycleData.cycle_start_date))
        .limit(6)
    )
    cycle_list = cycles.scalars().all()

    regularity = "unknown"
    if len(cycle_list) >= 3:
        lengths = [c.cycle_length for c in cycle_list if c.cycle_length]
        if lengths:
            variance = max(lengths) - min(lengths)
            if variance <= 2:
                regularity = "very_regular"
            elif variance <= 5:
                regularity = "regular"
            elif variance <= 10:
                regularity = "irregular"
            else:
                regularity = "very_irregular"

    return CycleOverview(
        current_cycle_day=current_cycle_day,
        current_phase=current_phase,
        next_period_date=next_period_date,
        days_until_period=days_until_period,
        cycle_regularity=regularity,
        avg_cycle_length=cycle_data.avg_cycle_length,
    )


@app.get("/api/v1/insights", response_model=List[HealthInsightResponse])
async def get_health_insights(
    current_user: Dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    limit: int = Query(10, ge=1, le=50),
):
    """Get personalized health insights"""

    result = await db.execute(
        select(HealthInsights)
        .filter(
            HealthInsights.user_id == current_user["user_id"],
            HealthInsights.is_dismissed == False,
        )
        .order_by(desc(HealthInsights.created_at))
        .limit(limit)
    )
    insights = result.scalars().all()

    return [HealthInsightResponse.model_validate(insight) for insight in insights]


@app.get("/api/v1/calendar/entries", response_model=List[CalendarEntryResponse])
async def get_all_calendar_entries(
    start_date: Optional[date] = None,
    end_date: Optional[date] = None,
    entry_type: Optional[EntryType] = None,
    current_user: Dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    limit: int = Query(100, ge=1, le=500),
):
    """Get all calendar entries for the current user"""
    
    query = select(CalendarEntry).filter(CalendarEntry.user_id == current_user["user_id"])
    
    if start_date:
        query = query.filter(CalendarEntry.entry_date >= start_date)
    if end_date:
        query = query.filter(CalendarEntry.entry_date <= end_date)
    if entry_type:
        query = query.filter(CalendarEntry.entry_type == entry_type.value)
    
    query = query.order_by(CalendarEntry.entry_date.desc()).limit(limit)
    
    result = await db.execute(query)
    entries = result.scalars().all()
    
    return [CalendarEntryResponse.model_validate(entry) for entry in entries]


@app.post("/api/v1/calendar/entries", response_model=CalendarEntryResponse, status_code=201)
async def create_calendar_entry(
    entry_data: CalendarEntryCreate,
    current_user: Dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Create a new calendar entry"""
    
    # Debug prints
    import logging
    logging.info(f"Current user: {current_user}")
    logging.info(f"Entry data: {entry_data}")
    
    try:
        # Check if entry already exists for this date and type
        existing = await db.execute(
            select(CalendarEntry).filter(
                and_(
                    CalendarEntry.user_id == current_user["user_id"],
                    CalendarEntry.entry_date == entry_data.entry_date,
                    CalendarEntry.entry_type == entry_data.entry_type.value,
                )
            )
        )
        if existing.scalars().first():
            raise HTTPException(
                status_code=400, detail="Entry already exists for this date and type"
            )
    except Exception as e:
        logging.error(f"Error checking for existing entry: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
    
    # Create new calendar entry
    new_entry = CalendarEntry(
        user_id=current_user["user_id"],
        entry_date=entry_data.entry_date,
        entry_type=entry_data.entry_type.value,
        flow_intensity=entry_data.flow_intensity.value if entry_data.flow_intensity else None,
        period_symptoms=entry_data.period_symptoms,
        mood=entry_data.mood.value if entry_data.mood else None,
        energy_level=entry_data.energy_level,
        sleep_hours=entry_data.sleep_hours,
        symptoms=entry_data.symptoms,
        medications=entry_data.medications,
        notes=entry_data.notes,
    )
    
    db.add(new_entry)
    await db.commit()
    await db.refresh(new_entry)
    
    # If this is a period entry, update cycle data
    if entry_data.entry_type == EntryType.PERIOD:
        await update_cycle_data(current_user["user_id"], entry_data.entry_date, db)
    
    return CalendarEntryResponse.model_validate(new_entry)

# Мобильный эндпоинт для создания записей календаря
@app.post("/api/v1/calendar/entries/mobile", response_model=CalendarEntryResponse, status_code=201)
async def create_mobile_calendar_entry_endpoint(
    mobile_entry: MobileCalendarEntryCreate,
    current_user: Dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Создать новую запись календаря из мобильного приложения"""
    import logging
    logging.info(f"Получены данные мобильного приложения: {mobile_entry.model_dump()}")
    
    try:
        # Преобразуем симптомы из списка в строку
        symptoms_str = ""
        if mobile_entry.symptoms:
            symptoms_str = ", ".join(mobile_entry.symptoms)
            logging.info(f"Преобразованы симптомы в строку: {symptoms_str}")
        
        # Преобразуем данные из мобильного формата в формат сервера
        server_entry = CalendarEntryCreate(
            entry_date=mobile_entry.date,
            entry_type=EntryType.PERIOD if mobile_entry.type == "MENSTRUATION" else 
                       EntryType.OVULATION if mobile_entry.type == "OVULATION" else 
                       EntryType.SYMPTOMS,
            flow_intensity=FlowIntensity.from_int(mobile_entry.flow_intensity) if mobile_entry.flow_intensity else None,
            mood=MoodType.from_mobile_mood(mobile_entry.mood) if mobile_entry.mood else None,
            symptoms=symptoms_str,
            notes=mobile_entry.notes,
            # Значения по умолчанию для обязательных полей сервера
            period_symptoms="",
            energy_level=1,  # Минимальное значение должно быть 1
            sleep_hours=0,
            medications="",
        )
        logging.info(f"Преобразовано в серверный формат: {server_entry}")
        
        # Проверяем существование записи
        existing = await db.execute(
            select(CalendarEntry).filter(
                and_(
                    CalendarEntry.user_id == current_user["user_id"],
                    CalendarEntry.entry_date == server_entry.entry_date,
                    CalendarEntry.entry_type == server_entry.entry_type.value,
                )
            )
        )
        existing_entry = existing.scalars().first()
        
        if existing_entry:
            logging.info(f"Найдена существующая запись с ID: {existing_entry.id}")
            # Если запись существует, обновляем её
            if server_entry.flow_intensity is not None:
                setattr(existing_entry, 'flow_intensity', server_entry.flow_intensity.value if server_entry.flow_intensity else None)
            if server_entry.symptoms is not None:
                setattr(existing_entry, 'symptoms', server_entry.symptoms)
            if server_entry.mood is not None:
                setattr(existing_entry, 'mood', server_entry.mood.value if server_entry.mood else None)
            if server_entry.notes is not None:
                setattr(existing_entry, 'notes', server_entry.notes)
                
            await db.commit()
            await db.refresh(existing_entry)
            logging.info("Существующая запись обновлена")
            
            return CalendarEntryResponse.model_validate(existing_entry)
        
        # Создаем новую запись в календаре
        new_entry = CalendarEntry(
            user_id=current_user["user_id"],
            entry_date=server_entry.entry_date,
            entry_type=server_entry.entry_type.value,
            flow_intensity=server_entry.flow_intensity.value if server_entry.flow_intensity else None,
            period_symptoms=server_entry.period_symptoms,
            mood=server_entry.mood.value if server_entry.mood else None,
            energy_level=server_entry.energy_level,
            sleep_hours=server_entry.sleep_hours,
            symptoms=server_entry.symptoms,
            medications=server_entry.medications,
            notes=server_entry.notes,
        )
        
        db.add(new_entry)
        await db.commit()
        await db.refresh(new_entry)
        logging.info(f"Создана новая запись с ID: {new_entry.id}")
        
        # Если это запись о менструации, обновляем данные цикла
        if server_entry.entry_type == EntryType.PERIOD:
            await update_cycle_data(current_user["user_id"], server_entry.entry_date, db)
            logging.info("Данные цикла обновлены")
        
        return CalendarEntryResponse.model_validate(new_entry)
    
    except Exception as e:
        logging.error(f"Ошибка при создании записи календаря: {str(e)}")
        await db.rollback()  # Откатываем транзакцию при ошибке
        raise HTTPException(status_code=500, detail=f"Ошибка сервера: {str(e)}")

@app.post("/debug/mobile-entry", status_code=200)
async def debug_mobile_calendar_entry(
    mobile_entry: MobileCalendarEntryCreate,
    db: AsyncSession = Depends(get_db),
):
    """Тестовый эндпоинт для проверки преобразования данных из мобильного формата (без создания записи)"""
    # Используем фиктивного пользователя для тестирования
    mock_user = {"user_id": 1, "username": "test_user"}
    
    # Преобразуем симптомы из списка в строку
    symptoms_str = ""
    if mobile_entry.symptoms:
        symptoms_str = ", ".join(mobile_entry.symptoms)
    
    # Преобразуем данные из мобильного формата в формат сервера
    server_entry = CalendarEntryCreate(
        entry_date=mobile_entry.date,
        entry_type=EntryType.PERIOD if mobile_entry.type == "MENSTRUATION" else 
                   EntryType.OVULATION if mobile_entry.type == "OVULATION" else 
                   EntryType.SYMPTOMS,
        flow_intensity=FlowIntensity.from_int(mobile_entry.flow_intensity) if mobile_entry.flow_intensity else None,
        mood=MoodType.from_mobile_mood(mobile_entry.mood) if mobile_entry.mood else None,
        symptoms=symptoms_str,
        notes=mobile_entry.notes,
        # Значения по умолчанию для обязательных полей сервера
        period_symptoms="",
        energy_level=1,  # Минимальное значение должно быть 1
        sleep_hours=0,
        medications="",
    )

    # Создаем ответ без сохранения в БД
    response_data = {
        "id": 0,  # Фиктивный ID
        "user_id": mock_user["user_id"],
        "entry_date": server_entry.entry_date.isoformat(),
        "entry_type": server_entry.entry_type.value,
        "flow_intensity": server_entry.flow_intensity.value if server_entry.flow_intensity else None,
        "period_symptoms": server_entry.period_symptoms,
        "mood": server_entry.mood.value if server_entry.mood else None,
        "energy_level": server_entry.energy_level,
        "sleep_hours": server_entry.sleep_hours,
        "symptoms": server_entry.symptoms,
        "medications": server_entry.medications,
        "notes": server_entry.notes,
        "created_at": date.today().isoformat(),
        "updated_at": date.today().isoformat(),
        "is_active": True
    }
    
    return {
        "message": "Данные успешно преобразованы из мобильного формата (без сохранения в БД)",
        "original_data": mobile_entry.model_dump(),
        "transformed_data": response_data
    }


@app.delete("/api/v1/entries/{entry_id}")
async def delete_calendar_entry(
    entry_id: int,
    current_user: Dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Delete calendar entry"""

    result = await db.execute(
        select(CalendarEntry).filter(
            and_(CalendarEntry.id == entry_id, CalendarEntry.user_id == current_user["user_id"])
        )
    )
    entry = result.scalars().first()

    if not entry:
        raise HTTPException(status_code=404, detail="Entry not found")

    await db.delete(entry)
    await db.commit()

    return {"message": "Entry deleted successfully"}

# Новый эндпоинт для мобильного приложения
@app.post("/api/v1/calendar/entry", response_model=schemas.CalendarEvent, status_code=201)
async def create_mobile_calendar_entry(
    entry_data: schemas.CalendarEventCreate,
    current_user: Dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Create a new calendar entry from mobile app"""
    import logging
    logging.info(f"Received mobile entry data: {entry_data}")
    
    # Преобразуем в серверный формат
    server_entry_data = entry_data.to_server_format()
    logging.info(f"Converted to server format: {server_entry_data}")
    
    # Проверяем существование записи
    try:
        existing = await db.execute(
            select(CalendarEntry).filter(
                and_(
                    CalendarEntry.user_id == current_user["user_id"],
                    CalendarEntry.entry_date == server_entry_data.entry_date,
                    CalendarEntry.entry_type == server_entry_data.entry_type.value,
                )
            )
        )
        existing_entry = existing.scalars().first()
        
        if existing_entry:
            # Если запись существует, обновляем её
            if server_entry_data.flow_intensity is not None:
                setattr(existing_entry, 'flow_intensity', server_entry_data.flow_intensity.value if server_entry_data.flow_intensity else None)
            if server_entry_data.symptoms is not None:
                setattr(existing_entry, 'symptoms', server_entry_data.symptoms)
            if server_entry_data.mood is not None:
                setattr(existing_entry, 'mood', server_entry_data.mood.value if server_entry_data.mood else None)
            if server_entry_data.notes is not None:
                setattr(existing_entry, 'notes', server_entry_data.notes)
                
            await db.commit()
            await db.refresh(existing_entry)
            
            # Возвращаем обновлённую запись
            response = schemas.CalendarEntryResponse.model_validate(existing_entry)
            return schemas.CalendarEvent.from_server_response(response)
            
        # Создаем новую запись
        db_entry = CalendarEntry(
            user_id=current_user["user_id"],
            entry_date=server_entry_data.entry_date,
            entry_type=server_entry_data.entry_type.value,
            flow_intensity=server_entry_data.flow_intensity.value if server_entry_data.flow_intensity else None,
            period_symptoms=server_entry_data.period_symptoms,
            mood=server_entry_data.mood.value if server_entry_data.mood else None,
            energy_level=server_entry_data.energy_level,
            sleep_hours=server_entry_data.sleep_hours,
            symptoms=server_entry_data.symptoms,
            medications=server_entry_data.medications,
            notes=server_entry_data.notes,
        )
        
        db.add(db_entry)
        await db.commit()
        await db.refresh(db_entry)
        
        # Если это запись о периоде, обновляем данные цикла
        if server_entry_data.entry_type == schemas.EntryType.PERIOD:
            await update_cycle_data(current_user["user_id"], server_entry_data.entry_date, db)
            
        # Преобразуем в формат для мобильного приложения
        response = schemas.CalendarEntryResponse.model_validate(db_entry)
        return schemas.CalendarEvent.from_server_response(response)
    
    except Exception as e:
        logging.error(f"Error creating calendar entry: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")


from .utils import safe_int, safe_str, safe_bool, safe_date, safe_datetime, safe_get_column_value

# Новый эндпоинт для мобильного приложения для получения записей календаря с фильтрацией по датам
@app.get("/api/v1/calendar/entries/mobile", response_model=MobileCalendarResponse)
async def get_mobile_calendar_entries(
    start_date: Optional[date] = Query(None, description="Начальная дата для фильтрации (включительно)"),
    end_date: Optional[date] = Query(None, description="Конечная дата для фильтрации (включительно)"),
    entry_type: Optional[str] = Query(None, description="Тип записи (MENSTRUATION, OVULATION и т.д.)"),
    current_user: Dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    limit: int = Query(100, ge=1, le=500, description="Максимальное количество записей"),
):
    """Получить записи календаря для мобильного приложения с фильтрацией по датам"""
    import logging
    logging.info(f"Запрос мобильных данных. start_date={start_date}, end_date={end_date}, entry_type={entry_type}")
    
    try:
        # Получаем записи из базы данных
        query = select(CalendarEntry).filter(CalendarEntry.user_id == current_user["user_id"])
        
        # Фильтрация по датам
        if start_date:
            query = query.filter(CalendarEntry.entry_date >= start_date)
        if end_date:
            query = query.filter(CalendarEntry.entry_date <= end_date)
        
        # Фильтрация по типу записи
        if entry_type:
            # Преобразуем тип из мобильного формата в серверный
            server_entry_type = None
            if entry_type == "MENSTRUATION":
                server_entry_type = EntryType.PERIOD.value
            elif entry_type == "OVULATION":
                server_entry_type = EntryType.OVULATION.value
            elif entry_type == "SYMPTOMS":
                server_entry_type = EntryType.SYMPTOMS.value
                
            if server_entry_type:
                query = query.filter(CalendarEntry.entry_type == server_entry_type)
        
        # Сортировка и ограничение количества записей
        query = query.order_by(desc(CalendarEntry.entry_date)).limit(limit)
        
        # Выполнение запроса
        result = await db.execute(query)
        entries = result.scalars().all()
        
        # Преобразуем записи в формат мобильного приложения
        mobile_entries = []
        for entry in entries:
            # Преобразуем тип записи из серверного формата в мобильный
            mobile_type = "SYMPTOMS"  # По умолчанию
            entry_type_value = safe_str(entry.entry_type, "")
            
            if entry_type_value == EntryType.PERIOD.value:
                mobile_type = "MENSTRUATION"
            elif entry_type_value == EntryType.OVULATION.value:
                mobile_type = "OVULATION"
                
            # Преобразуем симптомы из строки в список
            symptoms_list = []
            entry_symptoms = safe_str(entry.symptoms, "")
            if entry_symptoms:
                symptoms_list = [s.strip() for s in entry_symptoms.split(",")]
                
            # Преобразуем flow_intensity, если есть
            flow_intensity_value = None
            entry_flow = safe_str(entry.flow_intensity, "")
            if entry_flow in ['1', '2', '3', '4', '5']:
                flow_intensity_value = int(entry_flow)
                
            # Преобразуем mood, если есть
            mood_value = None
            entry_mood = safe_str(entry.mood, "")
            if entry_mood:
                mood_value = entry_mood.upper()
                
            # Преобразуем notes, если есть
            notes_value = safe_str(entry.notes, "")
                
            # Получаем created_at
            created_at_value = safe_datetime(
                getattr(entry, 'created_at', None), 
                datetime.now()
            ).isoformat()
                
            # Получаем is_predicted
            is_predicted_value = safe_bool(
                getattr(entry, 'is_predicted', None), 
                False
            )
            
            # Создаем мобильную запись
            mobile_entry = MobileCalendarEntryResponse(
                id=safe_int(entry.id),
                uuid=str(safe_int(entry.id)),  # Используем ID как UUID
                date=safe_date(entry.entry_date, date.today()).isoformat(),
                type=mobile_type,
                flow_intensity=flow_intensity_value,
                mood=mood_value,
                symptoms=symptoms_list,
                notes=notes_value,
                created_at=created_at_value,
                is_predicted=is_predicted_value
            )
            mobile_entries.append(mobile_entry)
        
        # Получаем информацию о текущем цикле
        current_cycle = await db.execute(
            select(CycleData)
            .filter(CycleData.user_id == current_user["user_id"])
            .order_by(desc(CycleData.cycle_start_date))
            .limit(1)
        )
        cycle_data = current_cycle.scalars().first()
        
        # Создаем информацию о периоде
        period_info = MobileCalendarPeriodInfo()
        prediction_info = MobilePredictionInfo()
        
        if cycle_data:
            # Заполняем информацию о текущем цикле
            cycle_start_date = safe_date(cycle_data.cycle_start_date)
            if cycle_start_date:
                period_info.current_cycle_start = cycle_start_date.isoformat()
            
            cycle_length = safe_int(cycle_data.cycle_length)
            if cycle_length > 0:
                period_info.cycle_length = cycle_length
            
            avg_cycle_length = safe_int(cycle_data.avg_cycle_length)
            if avg_cycle_length > 0:
                period_info.average_cycle_length = avg_cycle_length
                
                # Если есть информация о периоде, рассчитываем дату окончания
                period_length = safe_int(cycle_data.period_length)
                if period_length > 0 and cycle_start_date:
                    end_date_value = cycle_start_date + timedelta(days=period_length)
                    period_info.expected_period_end = end_date_value.isoformat()
                
                # Заполняем информацию о фертильном окне и овуляции
                if cycle_start_date:
                    ovulation_day = avg_cycle_length // 2
                    ovulation_date = cycle_start_date + timedelta(days=ovulation_day)
                    period_info.ovulation_date = ovulation_date.isoformat()
                    
                    # Фертильное окно начинается за 5 дней до овуляции и заканчивается через 1 день после
                    period_info.fertility_window_start = (ovulation_date - timedelta(days=5)).isoformat()
                    period_info.fertility_window_end = (ovulation_date + timedelta(days=1)).isoformat()
            
            # Заполняем прогноз
            next_period = safe_date(cycle_data.next_period_predicted)
            if next_period:
                prediction_info.next_period_date = next_period.isoformat()
                prediction_info.confidence_level = 80  # Приблизительное значение уверенности
                
                # Рассчитываем следующее фертильное окно и овуляцию
                if avg_cycle_length > 0:
                    next_ovulation = next_period - timedelta(days=avg_cycle_length // 2)
                    prediction_info.next_ovulation_date = next_ovulation.isoformat()
                    prediction_info.next_fertile_window_start = (next_ovulation - timedelta(days=5)).isoformat()
                    prediction_info.next_fertile_window_end = (next_ovulation + timedelta(days=1)).isoformat()
        
        # Собираем полный ответ
        response = MobileCalendarResponse(
            entries=mobile_entries,
            period_info=period_info,
            prediction=prediction_info
        )
        
        return response
    
    except Exception as e:
        logging.error(f"Ошибка при получении записей календаря: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Ошибка сервера: {str(e)}")


if __name__ == "__main__":
    import uvicorn
    from .mobile_responses import (
        MobileCalendarEntryResponse, 
        MobileCalendarPeriodInfo,
        MobilePredictionInfo, 
        MobileCalendarResponse
    )
    from .schemas_mobile import MobileFlowIntensity, MobileMood

    uvicorn.run(app, host="0.0.0.0", port=8004)
