# Analytics Cloud Functions Guide

## Overview

The Analytics Service supports **on-demand calculation via Cloud Functions**, allowing you to trigger fresh analytics calculations server-side and optionally cache the results.

## Available Cloud Functions

### 1. `calculateAnalyticsOnDemand` (Callable)

A callable Cloud Function that calculates analytics on-demand and optionally stores results in cache.

**Location**: `Cloud/functions/src/analytics/calculateAnalyticsOnDemand.ts`

## Usage

### Using the Client Service Helper

```typescript
import { AnalyticsCloudService } from '@blackcode_sa/metaestetics-api';
import { getApp } from 'firebase/app';

const app = getApp();
const cloudService = new AnalyticsCloudService(app);

// Calculate dashboard analytics on-demand
const dashboard = await cloudService.calculateDashboard(
  { clinicBranchId: 'clinic-123' },
  { start: new Date('2024-01-01'), end: new Date('2024-12-31') },
  { storeInCache: true } // Store result for future use
);
```

### Direct Callable Function Usage

```typescript
import { getFunctions, httpsCallable } from 'firebase/functions';
import { getApp } from 'firebase/app';

const functions = getFunctions(getApp(), 'europe-west6');
const calculateAnalytics = httpsCallable(functions, 'calculateAnalyticsOnDemand');

// Calculate revenue metrics grouped by practitioner
const result = await calculateAnalytics({
  analyticsType: 'revenueByEntity',
  groupBy: 'practitioner',
  filters: { clinicBranchId: 'clinic-123' },
  dateRange: {
    start: '2024-01-01T00:00:00Z',
    end: '2024-12-31T23:59:59Z',
  },
  options: {
    storeInCache: true, // Store in cache after calculation
    useCache: false,    // Force fresh calculation
  },
});

const revenueByPractitioner = result.data.data;
```

## Supported Analytics Types

### Top-Level Analytics

- `dashboard` - Complete dashboard analytics
- `practitioner` - Individual practitioner analytics (requires `entityId`)
- `procedure` - Individual procedure analytics (requires `entityId`)
- `clinic` - Clinic-level analytics
- `timeEfficiency` - Time efficiency metrics
- `revenue` - Revenue metrics
- `productUsage` - Product usage metrics
- `patient` - Patient analytics (optional `entityId`)

### Grouped Analytics

- `revenueByEntity` - Revenue grouped by clinic/practitioner/procedure/patient/technology (requires `groupBy`)
- `productUsageByEntity` - Product usage grouped by entity (requires `groupBy`)
- `timeEfficiencyByEntity` - Time efficiency grouped by entity (requires `groupBy`)
- `patientBehaviorByEntity` - Patient behavior grouped by entity (requires `groupBy`)
- `cancellation` - Cancellation metrics grouped by entity (requires `groupBy`)
- `noShow` - No-show metrics grouped by entity (requires `groupBy`)

## Request Parameters

```typescript
interface CalculateAnalyticsRequest {
  analyticsType: string;        // Required: Type of analytics to calculate
  filters?: AnalyticsFilters;   // Optional: Filters (clinicBranchId, etc.)
  dateRange?: {                 // Optional: Date range
    start: string;              // ISO date string
    end: string;                // ISO date string
  };
  entityId?: string;            // Required for practitioner/procedure/patient
  groupBy?: EntityType;         // Required for grouped analytics
  options?: {
    storeInCache?: boolean;     // Default: true - Store result in cache
    useCache?: boolean;         // Default: false - Use cache if available
    maxCacheAgeHours?: number;  // Default: 12 - Max cache age
  };
}
```

## Response Format

```typescript
interface CalculateAnalyticsResponse {
  success: boolean;
  data: any;                    // The calculated analytics data
  computedAt: string;           // ISO timestamp of when it was computed
}
```

## Examples

### Example 1: Calculate Dashboard Analytics

```typescript
const dashboard = await cloudService.calculateDashboard(
  { clinicBranchId: 'clinic-123' },
  { start: new Date('2024-01-01'), end: new Date('2024-12-31') },
  { storeInCache: true }
);
```

### Example 2: Calculate Revenue by Technology

```typescript
const revenueByTechnology = await cloudService.calculateRevenueByEntity(
  'technology',
  { start: new Date('2024-01-01'), end: new Date('2024-12-31') },
  { clinicBranchId: 'clinic-123' },
  { storeInCache: true }
);
```

### Example 3: Force Fresh Calculation (Bypass Cache)

```typescript
const result = await calculateAnalytics({
  analyticsType: 'dashboard',
  filters: { clinicBranchId: 'clinic-123' },
  dateRange: {
    start: '2024-01-01T00:00:00Z',
    end: '2024-12-31T23:59:59Z',
  },
  options: {
    useCache: false,      // Don't use cache
    storeInCache: true,   // But store the result
  },
});
```

### Example 4: Calculate Practitioner Analytics

```typescript
const practitionerMetrics = await cloudService.calculatePractitioner(
  'practitioner-123',
  { start: new Date('2024-01-01'), end: new Date('2024-12-31') },
  {
    storeInCache: true,
    clinicBranchId: 'clinic-123',
  }
);
```

## Benefits

### Performance
- **Server-side computation**: Faster than client-side for large datasets
- **Parallel processing**: Cloud Functions can handle multiple requests simultaneously
- **No client resource usage**: Computation happens in the cloud

### Caching
- **Automatic caching**: Results can be stored automatically
- **Future reads**: Cached results can be read instantly by `AnalyticsService`
- **Configurable**: Control whether to use/store cache

### Cost Optimization
- **Efficient**: Server-side computation is optimized
- **Scalable**: Handles large datasets without client limitations
- **Predictable**: Fixed cost per calculation

## When to Use

### Use Cloud Function When:
- ✅ Cache is stale and you need fresh data immediately
- ✅ Calculating analytics for large date ranges
- ✅ Need to calculate multiple analytics types
- ✅ Want to store results for future use
- ✅ Client device has limited resources

### Use Client Service When:
- ✅ Cache is fresh (< 12 hours old)
- ✅ Small date ranges
- ✅ Quick reads from cache
- ✅ Offline-first scenarios

## Error Handling

```typescript
try {
  const result = await cloudService.calculateDashboard(...);
} catch (error) {
  if (error.code === 'invalid-argument') {
    // Invalid parameters provided
  } else if (error.code === 'internal') {
    // Server error during calculation
  }
}
```

## Integration with AnalyticsService

The Cloud Function works seamlessly with `AnalyticsService`:

1. **Client checks cache first** (via `AnalyticsService`)
2. **If cache is stale/missing**, call Cloud Function
3. **Cloud Function calculates** and optionally stores result
4. **Future reads** use the cached data

This creates a **hybrid approach**:
- Fast reads from cache (default)
- On-demand fresh calculations when needed
- Automatic caching for future use

