from fastapi import APIRouter, HTTPException, Query, Depends
from pydantic import BaseModel, Field
from typing import List, Optional
import datetime
from dbmodel import Study, Instance, SendLog
from peewee import fn
import shutil
import os
import logging
from config import config
from ..dependencies import get_db

LOGGER = logging.getLogger('sampacs')

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


class AnalyticsChartItem(BaseModel):
    """Analytics chart item"""
    date: str = Field(description="Date in YYYY-MM-DD format")
    count: int = Field(description="Count for the specified date")


class StorageDiskUsage(BaseModel):
    """Storage disk usage information"""
    total: int = Field(description="Total disk space in bytes")
    used: int = Field(description="Used disk space in bytes")


class AnalyticsCharts(BaseModel):
    """Analytics charts data"""
    studies: List[AnalyticsChartItem] = Field(description="Studies count statistics by day")
    instances: List[AnalyticsChartItem] = Field(description="Instances (images) count statistics by day")
    pacsTransfers: List[AnalyticsChartItem] = Field(description="PACS transfers count statistics by day")
    storageCapacity: List[AnalyticsChartItem] = Field(description="Storage capacity statistics (temporarily unused)")
    storageDiskUsage: StorageDiskUsage = Field(description="Storage disk usage information")


def get_disk_usage(path) -> StorageDiskUsage | None:
    try:
        if not os.path.exists(path):
            LOGGER.error(f"error '{path}' not exists")
            return None

        usage = shutil.disk_usage(path)
        return StorageDiskUsage(
            total = usage.total,
            used = usage.used
        )
    except Exception as e:
        LOGGER.error(f"'{path}': {e}")
        return None

class AnalyticsResponse(BaseModel):
    """Analytics API response"""
    charts: AnalyticsCharts = Field(description="Data for all analytics charts")


@router.get("", response_model=AnalyticsResponse, summary="Получить аналитические данные", response_description="Аналитические данные за указанный период")
async def get_analytics(
    dateFrom: datetime.date = Query(..., description="Start date in YYYY-MM-DD format"),
    dateTo: datetime.date = Query(..., description="End date in YYYY-MM-DD format"),
    aetitle: Optional[str] = Query(None, description="Filter by modality AETitle"),
    db: None = Depends(get_db)
):
    """
    Получить аналитические данные за указанный период времени.

    Возвращает агрегированную статистику по дням для:
    - Количества исследований (studies)
    - Количества инстансов (изображений) (instances)
    - Количества PACS трансферов (передач данных между системами)
    - Использования хранилища (storageCapacity - по дням, storageDiskUsage - общее использование)

    ## Фильтрация
    - По дате исследования (обязательные параметры)
    - По модальности (AETitle, опционально)

    ## Поля ответа
    - **studies**: Количество исследований по дням
    - **instances**: Количество инстансов (изображений) по дням
    - **pacsTransfers**: Количество PACS трансферов по дням
    - **storageCapacity**: Использование хранилища по дням (в байтах)
    - **storageDiskUsage**: Общая информация об использовании дискового пространства
    """

    # Initialize response structure
    res = AnalyticsResponse(
        charts=AnalyticsCharts(
            studies=[],
            instances=[],
            pacsTransfers=[],
            storageCapacity=[],
            #storageDiskUsage={"total": 46068373200896, "used": 34082548629504}
            storageDiskUsage={"total": 0, "used": 0}
        )
    )

    try:
        # Get studies count per day
        query = Study.select(
            Study.date,
            fn.COUNT(Study.uid).alias('count')
        ).where(
            Study.date.between(dateFrom, dateTo)
        ).group_by(Study.date)

        if aetitle:
            query = query.where(Study.creator_aetitle == aetitle)

        for row in query:
            res.charts.studies.append(
                AnalyticsChartItem(
                    date=row.date.strftime('%Y-%m-%d'),
                    count=row.count
                )
            )

        # Get instances count per day
        query = Instance.select(
            Instance.study_date,
            fn.COUNT(Instance.uid).alias('count')
        ).where(
            Instance.study_date.between(dateFrom, dateTo)
        ).group_by(Instance.study_date)

        for row in query:
            res.charts.instances.append(
                AnalyticsChartItem(
                    date=row.study_date.strftime('%Y-%m-%d'),
                    count=row.count
                )
            )

        # Get PACS transfers count per day
        query = SendLog.select(
            fn.DATE(SendLog.sent).alias('sent'),
            fn.COUNT(SendLog.instance_uid).alias('count')
        ).where(
            SendLog.sent.between(dateFrom, dateTo)
        ).group_by(fn.DATE(SendLog.sent))

        for row in query:
            res.charts.pacsTransfers.append(
                AnalyticsChartItem(
                    date=row.sent.strftime('%Y-%m-%d'),
                    count=row.count
                )
            )

        # Get storage capacity usage per day (sum of study.bytes)
        query = Study.select(
            Study.date,
            fn.SUM(Study.size).alias('count')
        ).where(
            Study.date.between(dateFrom, dateTo)
        ).group_by(Study.date)

        if aetitle:
            query = query.where(Study.creator_aetitle == aetitle)

        for row in query:
            res.charts.storageCapacity.append(
                AnalyticsChartItem(
                    date=row.date.strftime('%Y-%m-%d'),
                    count=row.count or 0  # Handle NULL values
                )
            )

        disk_usage = get_disk_usage(config.storageDir)
        if disk_usage:
            res.charts.storageDiskUsage = disk_usage

        return res

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error fetching analytics data: {str(e)}")
