# Analytics Service - Quick Start Guide

## 🚀 What We Can Do

The Analytics Service provides **comprehensive insights** into your clinic operations:

- **Financial Intelligence**: Revenue, costs, payment tracking
- **Practitioner Performance**: Doctor efficiency, cancellations, revenue
- **Procedure Analytics**: Popularity, profitability, product usage
- **Time Management**: Booked vs actual time, efficiency
- **Cancellation & No-Show Analysis**: Rates by clinic/doctor/patient/procedure
- **Patient Insights**: Lifetime value, retention, behavior
- **Product Usage**: Usage patterns, revenue contribution
- **Clinic Performance**: Overall metrics and comparisons

---

## 🔄 How It Works: Computed vs On-Demand

### **Pre-Computed Analytics** (Default - Recommended) ⚡

**How:**
1. Cloud Function runs **every 12 hours**
2. Computes analytics for all clinics
3. Stores in Firestore: `clinics/{clinicBranchId}/analytics/`
4. Client reads cached data (instant!)

**Benefits:**
- ⚡ **Fast**: 1 document read = instant response
- 💰 **Cheap**: 1 read vs hundreds/thousands
- 📈 **Scalable**: Works with large datasets

**Example:**
```typescript
// Automatically uses cached data if fresh (< 12 hours)
const dashboard = await analyticsService.getDashboardData(
  { clinicBranchId: 'clinic-123' },
  { start: new Date('2024-01-01'), end: new Date('2024-12-31') }
);
// Returns instantly! ⚡
```

### **On-Demand Calculation** (Fallback) 🔄

**When:**
- No cached data exists
- Cache is stale (> 12 hours)
- You set `useCache: false`
- Custom date ranges

**How:**
1. Queries all appointments
2. Calculates metrics in real-time
3. Returns results

**Example:**
```typescript
// Force on-demand calculation
const dashboard = await analyticsService.getDashboardData(
  { clinicBranchId: 'clinic-123' },
  dateRange,
  { useCache: false } // Force calculation
);
```

---

## 📊 Available Analytics

### 1. **Practitioner Analytics** 👨‍⚕️
```typescript
const metrics = await analyticsService.getPractitionerAnalytics(
  'practitioner-id',
  dateRange
);
// Returns: appointments, cancellations, no-shows, revenue, time efficiency, etc.
```

### 2. **Procedure Analytics** 🏥
```typescript
// Single procedure
const procedure = await analyticsService.getProcedureAnalytics('procedure-id', dateRange);

// All procedures
const all = await analyticsService.getProcedureAnalytics(undefined, dateRange);

// Most popular
const popular = await analyticsService.getProcedurePopularity(dateRange, 10);

// Most profitable
const profitable = await analyticsService.getProcedureProfitability(dateRange, 10);
```

### 3. **Time Efficiency** ⏱️
```typescript
const time = await analyticsService.getTimeEfficiencyMetrics(
  { clinicBranchId: 'clinic-123' },
  dateRange
);
// Returns: efficiency %, overrun, underutilization, etc.
```

### 4. **Cancellation Metrics** ❌
```typescript
const cancellations = await analyticsService.getCancellationMetrics(
  'practitioner', // or 'clinic', 'patient', 'procedure'
  dateRange
);
// Returns array with cancellation rates, reasons, lead times
```

### 5. **No-Show Metrics** 🚫
```typescript
const noShows = await analyticsService.getNoShowMetrics(
  'practitioner', // or 'clinic', 'patient', 'procedure'
  dateRange
);
// Returns array with no-show rates per entity
```

### 6. **Revenue Metrics** 💰
```typescript
const revenue = await analyticsService.getRevenueMetrics(
  { clinicBranchId: 'clinic-123' },
  dateRange
);
// Returns: total revenue, by status, by payment status, unpaid, etc.
```

### 7. **Product Usage** 📦
```typescript
const products = await analyticsService.getProductUsageMetrics(
  undefined, // or 'product-id'
  dateRange
);
// Returns: usage counts, revenue, quantities per product
```

### 8. **Patient Analytics** 👥
```typescript
const patient = await analyticsService.getPatientAnalytics(
  'patient-id', // or undefined for all
  dateRange
);
// Returns: lifetime value, retention, frequency, etc.
```

### 9. **Dashboard Data** 📊
```typescript
const dashboard = await analyticsService.getDashboardData(
  { clinicBranchId: 'clinic-123' },
  dateRange
);
// Returns: comprehensive dashboard with all metrics
```

---

## 🎯 Specific Use Case: Patient No-Show Per Doctor

### **Question**: "Which patients have the highest no-show rate for each doctor?"

### **Solution 1: No-Show Rates by Practitioner** ✅

```typescript
// Get no-show metrics grouped by practitioner (doctor)
const noShowByPractitioner = await analyticsService.getNoShowMetrics(
  'practitioner',
  { start: new Date('2024-01-01'), end: new Date('2024-12-31') }
);

// Returns array:
// [
//   {
//     entityId: 'practitioner-123',
//     entityName: 'Dr. Smith',
//     entityType: 'practitioner',
//     totalAppointments: 100,
//     noShowAppointments: 15,
//     noShowRate: 15.0  // 15%
//   },
//   ...
// ]

// Sort by no-show rate (highest first)
const sorted = noShowByPractitioner
  .sort((a, b) => b.noShowRate - a.noShowRate);

console.log('Doctors ranked by no-show rate:');
sorted.forEach((doctor, index) => {
  console.log(`${index + 1}. ${doctor.entityName}: ${doctor.noShowRate}%`);
});
```

### **Solution 2: Patient No-Shows for a Specific Doctor** ✅

```typescript
// Step 1: Get all appointments for a specific practitioner
const practitionerId = 'practitioner-123';
const dateRange = { start: new Date('2024-01-01'), end: new Date('2024-12-31') };

// Get practitioner analytics (includes no-show count)
const practitionerMetrics = await analyticsService.getPractitionerAnalytics(
  practitionerId,
  dateRange
);

console.log(`Dr. ${practitionerMetrics.practitionerName}:`);
console.log(`  Total Appointments: ${practitionerMetrics.totalAppointments}`);
console.log(`  No-Shows: ${practitionerMetrics.noShowAppointments}`);
console.log(`  No-Show Rate: ${practitionerMetrics.noShowRate}%`);

// Step 2: Get patient-level breakdown for this doctor
// (You can filter appointments manually or use patient analytics)

// Get patient analytics filtered by practitioner
const allPatients = await analyticsService.getPatientAnalytics(undefined, dateRange);

// Filter patients who had appointments with this practitioner
// and calculate their no-show rates
const patientsWithThisDoctor = allPatients
  .filter(patient => {
    // Check if patient had appointments with this practitioner
    // (You'd need to query appointments or enhance patient analytics)
    return true; // Placeholder
  })
  .sort((a, b) => b.noShowRate - a.noShowRate);

console.log('\nPatients with highest no-show rates for this doctor:');
patientsWithThisDoctor.slice(0, 10).forEach((patient, index) => {
  console.log(`${index + 1}. ${patient.patientName}: ${patient.noShowRate}%`);
});
```

### **Solution 3: Cross-Analysis (No-Shows by Patient AND Doctor)** ✅

```typescript
// Get no-shows grouped by patient
const noShowByPatient = await analyticsService.getNoShowMetrics(
  'patient',
  dateRange
);

// Get no-shows grouped by practitioner
const noShowByPractitioner = await analyticsService.getNoShowMetrics(
  'practitioner',
  dateRange
);

// For detailed cross-analysis, you can:
// 1. Get all appointments
// 2. Filter no-shows
// 3. Group by practitioner AND patient
const appointments = await analyticsService['fetchAppointments'](
  undefined,
  dateRange
);

const noShows = appointments.filter(a => a.status === AppointmentStatus.NO_SHOW);

// Create a map: practitioner -> patients -> no-show count
const practitionerPatientMap = new Map<
  string,
  Map<string, { patientName: string; noShowCount: number; totalAppointments: number }>
>();

appointments.forEach(appointment => {
  const practitionerId = appointment.practitionerId;
  const patientId = appointment.patientId;
  const patientName = appointment.patientInfo?.fullName || 'Unknown';

  if (!practitionerPatientMap.has(practitionerId)) {
    practitionerPatientMap.set(practitionerId, new Map());
  }

  const patientMap = practitionerPatientMap.get(practitionerId)!;
  if (!patientMap.has(patientId)) {
    patientMap.set(patientId, { patientName, noShowCount: 0, totalAppointments: 0 });
  }

  const patientData = patientMap.get(patientId)!;
  patientData.totalAppointments++;

  if (appointment.status === AppointmentStatus.NO_SHOW) {
    patientData.noShowCount++;
  }
});

// Display results
practitionerPatientMap.forEach((patientMap, practitionerId) => {
  const practitioner = appointments.find(a => a.practitionerId === practitionerId);
  const practitionerName = practitioner?.practitionerInfo?.name || 'Unknown';

  console.log(`\n${practitionerName}:`);
  
  const patientRates = Array.from(patientMap.entries())
    .map(([patientId, data]) => ({
      patientId,
      patientName: data.patientName,
      noShowRate: (data.noShowCount / data.totalAppointments) * 100,
      noShowCount: data.noShowCount,
      totalAppointments: data.totalAppointments,
    }))
    .sort((a, b) => b.noShowRate - a.noShowRate);

  patientRates.forEach(patient => {
    console.log(`  ${patient.patientName}: ${patient.noShowRate.toFixed(1)}% (${patient.noShowCount}/${patient.totalAppointments})`);
  });
});
```

---

## 📝 Quick Examples

### Example 1: Doctor Performance Dashboard
```typescript
const practitionerMetrics = await analyticsService.getPractitionerAnalytics(
  'practitioner-id',
  dateRange
);

console.log(`Doctor: ${practitionerMetrics.practitionerName}`);
console.log(`Appointments: ${practitionerMetrics.totalAppointments}`);
console.log(`Cancellation Rate: ${practitionerMetrics.cancellationRate}%`);
console.log(`No-Show Rate: ${practitionerMetrics.noShowRate}%`);
console.log(`Time Efficiency: ${practitionerMetrics.timeEfficiency}%`);
console.log(`Total Revenue: ${practitionerMetrics.totalRevenue} ${practitionerMetrics.currency}`);
```

### Example 2: Top Procedures by Revenue
```typescript
const topProcedures = await analyticsService.getProcedureProfitability(
  dateRange,
  10
);

topProcedures.forEach((procedure, index) => {
  console.log(`${index + 1}. ${procedure.procedureName}`);
  console.log(`   Revenue: ${procedure.totalRevenue}`);
  console.log(`   Appointments: ${procedure.appointmentCount}`);
});
```

### Example 3: Clinic Comparison
```typescript
const clinic1 = await analyticsService.getClinicAnalytics('clinic-1', dateRange);
const clinic2 = await analyticsService.getClinicAnalytics('clinic-2', dateRange);

console.log('Clinic Comparison:');
console.log(`Clinic 1 Revenue: ${clinic1.totalRevenue}`);
console.log(`Clinic 2 Revenue: ${clinic2.totalRevenue}`);
console.log(`Clinic 1 Cancellation Rate: ${clinic1.cancellationRate}%`);
console.log(`Clinic 2 Cancellation Rate: ${clinic2.cancellationRate}%`);
```

---

## 🎛️ Configuration

### Change Cache Freshness
```typescript
// Use cache if data is less than 6 hours old
const metrics = await analyticsService.getPractitionerAnalytics(
  practitionerId,
  dateRange,
  { maxCacheAgeHours: 6 }
);
```

### Force On-Demand Calculation
```typescript
const metrics = await analyticsService.getPractitionerAnalytics(
  practitionerId,
  dateRange,
  { useCache: false }
);
```

### Change Cloud Function Schedule
Edit `Cloud/functions/src/analytics/computeAnalytics.ts`:
```typescript
schedule: "every 6 hours" // or "every 24 hours"
```

---

## 📚 Full Documentation

- **Usage Guide**: `USAGE_GUIDE.md` - Complete guide with all use cases
- **Architecture**: `ARCHITECTURE.md` - How computed vs on-demand works
- **README**: `README.md` - API reference

