# Heat User - Aggregation Tables

## 📋 Tổng quan

Ngoài bảng `student_study_sessions` track từng session riêng lẻ, hệ thống có thêm **2 bảng aggregation** để query nhanh:

1. **`student_history_study_time`**: Tổng thời gian theo `id_history` (per part)
2. **`student_contest_study_time`**: Tổng thời gian theo `id_history_contest` (per contest)

---

## 🗄️ Bảng 1: student_history_study_time

### **Mục đích:**
Track tổng thời gian học sinh làm **1 phần cụ thể** (1 idHistory), có thể qua **nhiều sessions** (nếu có continue).

### **Schema:**

```sql
CREATE TABLE student_history_study_time (
    id BIGINT PRIMARY KEY,
    student_id BIGINT NOT NULL,
    id_history BIGINT NOT NULL,
    id_bai_kiem_tra BIGINT,
    
    total_minutes DECIMAL(10,2) DEFAULT 0,     -- Tổng thời gian
    session_count INT DEFAULT 0,                -- Số sessions
    status ENUM('in_progress', 'completed', 'stopped'),
    
    first_started_at DATETIME,                  -- Lần đầu start
    last_activity_at DATETIME,                  -- Lần cuối có activity
    completed_at DATETIME,                      -- Thời gian submit
    
    UNIQUE(student_id, id_history)
);
```

### **Use Case:**

**Câu hỏi:** "Học sinh này làm phần Reading (idHistory: 201) mất bao lâu?"

```sql
SELECT * FROM student_history_study_time
WHERE student_id = 123 AND id_history = 201;

Result:
┌────┬─────────┬────────────┬───────────────┬───────────────┐
│ id │ student │ id_history │ total_minutes │ session_count │
├────┼─────────┼────────────┼───────────────┼───────────────┤
│ 1  │ 123     │ 201        │ 35.5          │ 2             │
└────┴─────────┴────────────┴───────────────┴───────────────┘

Giải thích: Học sinh 123 làm Reading (201) tổng 35.5 phút qua 2 sessions
            (ví dụ: session 1 = 20 phút, close browser, session 2 = 15.5 phút)
```

---

## 🗄️ Bảng 2: student_contest_study_time

### **Mục đích:**
Track tổng thời gian học sinh hoàn thành **toàn bộ contest** (1 idHistoryContest), bao gồm **tất cả parts**.

### **Schema:**

```sql
CREATE TABLE student_contest_study_time (
    id BIGINT PRIMARY KEY,
    student_id BIGINT NOT NULL,
    id_history_contest BIGINT NOT NULL,
    id_bai_kiem_tra BIGINT,
    contest_type INT,                           -- 29=single, khác=multi
    
    total_minutes DECIMAL(10,2) DEFAULT 0,     -- Tổng thời gian ALL parts
    total_sessions INT DEFAULT 0,               -- Tổng sessions ALL parts
    parts_completed INT DEFAULT 0,              -- Số parts đã hoàn thành
    total_parts INT DEFAULT 1,                  -- Tổng số parts
    status ENUM('in_progress', 'completed', 'stopped'),
    
    first_started_at DATETIME,                  -- Lần đầu start contest
    last_activity_at DATETIME,                  -- Lần cuối có activity
    completed_at DATETIME,                      -- Thời gian hoàn thành tất cả
    
    UNIQUE(student_id, id_history_contest)
);
```

### **Use Case:**

**Câu hỏi:** "Học sinh này làm bộ đề IELTS (idHistoryContest: 100) mất bao lâu?"

```sql
SELECT * FROM student_contest_study_time
WHERE student_id = 123 AND id_history_contest = 100;

Result:
┌────┬─────────┬──────────────┬───────────────┬────────────┬────────────┐
│ id │ student │ id_history_  │ total_minutes │ parts_     │ total_     │
│    │         │ contest      │               │ completed  │ parts      │
├────┼─────────┼──────────────┼───────────────┼────────────┼────────────┤
│ 1  │ 123     │ 100          │ 120.5         │ 4          │ 4          │
└────┴─────────┴──────────────┴───────────────┴────────────┴────────────┘

Giải thích: Học sinh 123 làm IELTS (100) tổng 120.5 phút
            Đã hoàn thành 4/4 parts (Reading + Listening + Writing + Speaking)
```

---

## 🔄 Cách hoạt động

### **Khi nào dữ liệu được update?**

Mỗi khi **end session** (submit, stop, auto-end), Backend sẽ:

```php
// 1. End session
endSessionWithTime($session, $endTime, $status);

// 2. Update daily stats
distributeDailyTime($session, $startTime, $endTime);

// 3. Update history-level aggregation ⭐ MỚI
updateHistoryStudyTime($session, $minutes, $status);

// 4. Update contest-level aggregation ⭐ MỚI
updateContestStudyTime($session, $minutes, $status);
```

---

## 📊 Ví dụ thực tế

### **Scenario: Multi-part IELTS**

```
idHistoryContest: 100 (IELTS)
├── idHistory: 201 (Reading)
├── idHistory: 202 (Listening)
├── idHistory: 203 (Writing)
└── idHistory: 204 (Speaking)
```

### **Timeline:**

```
=== PART 1: READING ===

[09:00] Start Reading (idHistory: 201) → session 1
[09:10] Close browser
[09:20] Cron auto-end session 1 → 10 phút

Backend updates:
✅ student_history_study_time (201):
   - total_minutes: 15 (min rule)
   - session_count: 1
   - status: in_progress

✅ student_contest_study_time (100):
   - total_minutes: 15
   - total_sessions: 1
   - parts_completed: 0 (chưa submit)

[14:00] Continue Reading → session 2
[14:20] Submit Reading → 20 phút

Backend updates:
✅ student_history_study_time (201):
   - total_minutes: 35 (15 + 20)
   - session_count: 2
   - status: completed ✓

✅ student_contest_study_time (100):
   - total_minutes: 35
   - total_sessions: 2
   - parts_completed: 1 (Reading done)

=== PART 2: LISTENING ===

[14:25] Start Listening (idHistory: 202) → session 3
[14:40] Submit → 15 phút

Backend updates:
✅ student_history_study_time (202): ← NEW RECORD
   - total_minutes: 15
   - session_count: 1
   - status: completed

✅ student_contest_study_time (100): ← UPDATE EXISTING
   - total_minutes: 50 (35 + 15)
   - total_sessions: 3
   - parts_completed: 2 (Reading + Listening)

=== PART 3 & 4 ===

[Similar...]

=== KẾT QUẢ CUỐI CÙNG ===

student_history_study_time:
┌────┬─────────┬────────────┬───────────────┬────────────┬───────────┐
│ id │ student │ id_history │ total_minutes │ session_   │ status    │
│    │         │            │               │ count      │           │
├────┼─────────┼────────────┼───────────────┼────────────┼───────────┤
│ 1  │ 123     │ 201        │ 35.0          │ 2          │ completed │
│ 2  │ 123     │ 202        │ 15.0          │ 1          │ completed │
│ 3  │ 123     │ 203        │ 45.0          │ 3          │ completed │
│ 4  │ 123     │ 204        │ 25.5          │ 1          │ completed │
└────┴─────────┴────────────┴───────────────┴────────────┴───────────┘

student_contest_study_time:
┌────┬─────────┬──────────────┬───────────────┬───────────┬──────────┐
│ id │ student │ id_history_  │ total_minutes │ parts_    │ total_   │
│    │         │ contest      │               │ completed │ parts    │
├────┼─────────┼──────────────┼───────────────┼───────────┼──────────┤
│ 1  │ 123     │ 100          │ 120.5         │ 4         │ 4        │
└────┴─────────┴──────────────┴───────────────┴───────────┴──────────┘
                                ↑ 35+15+45+25.5
```

---

## 📡 API Endpoints

### **1. Get History Study Time**

```
GET /api/heat-user/study-session/history-time?id_history=201&student_id=123

Response:
{
  "success": true,
  "data": {
    "student_id": 123,
    "id_history": 201,
    "total_minutes": 35.0,
    "formatted_time": "00:35",
    "session_count": 2,
    "status": "completed",
    "first_started_at": "2025-12-04 09:00:00",
    "completed_at": "2025-12-04 14:20:00"
  }
}
```

**Use case:** 
- Hiển thị "Bạn đã làm phần Reading trong 35 phút"
- Check xem phần này đã hoàn thành chưa

---

### **2. Get Contest Study Time**

```
GET /api/heat-user/study-session/contest-time?id_history_contest=100&student_id=123

Response:
{
  "success": true,
  "data": {
    "student_id": 123,
    "id_history_contest": 100,
    "contest_type": 30,
    "total_minutes": 120.5,
    "formatted_time": "02:00",
    "total_sessions": 7,
    "parts_completed": 4,
    "total_parts": 4,
    "completion_percentage": 100,
    "status": "completed",
    "first_started_at": "2025-12-04 09:00:00",
    "completed_at": "2025-12-04 16:30:00"
  }
}
```

**Use case:**
- Hiển thị "Bạn đã hoàn thành bộ đề IELTS trong 2 giờ"
- Progress bar: "3/4 parts completed"
- Check xem đã làm xong tất cả chưa

---

## 🎯 Benefits

### **1. Query Performance:**

❌ **Không có aggregation tables:**
```sql
-- Phải sum từ nhiều sessions
SELECT SUM(adjusted_duration_seconds) / 60 as total_minutes
FROM student_study_sessions
WHERE student_id = 123 AND id_history_contest = 100;

-- Slow nếu có nhiều sessions
```

✅ **Có aggregation tables:**
```sql
-- Chỉ 1 query đơn giản
SELECT total_minutes 
FROM student_contest_study_time
WHERE student_id = 123 AND id_history_contest = 100;

-- Fast!
```

---

### **2. Easy to Query:**

```sql
-- Top 10 học sinh làm nhanh nhất bộ đề IELTS
SELECT student_id, total_minutes, formatted_time
FROM student_contest_study_time
WHERE id_history_contest = 100 
  AND status = 'completed'
ORDER BY total_minutes ASC
LIMIT 10;

-- Trung bình thời gian làm phần Reading
SELECT AVG(total_minutes) as avg_minutes
FROM student_history_study_time
WHERE id_history = 201
  AND status = 'completed';

-- Học sinh nào chưa hoàn thành?
SELECT student_id, parts_completed, total_parts
FROM student_contest_study_time
WHERE id_history_contest = 100
  AND status = 'in_progress';
```

---

### **3. Frontend Display:**

```javascript
// Example: Progress display
const response = await fetch('/api/heat-user/study-session/contest-time?id_history_contest=100');
const data = await response.json();

// Show progress
console.log(`Progress: ${data.parts_completed}/${data.total_parts} parts`);
console.log(`Time spent: ${data.formatted_time}`);
console.log(`Completion: ${data.completion_percentage}%`);
```

---

## 📋 Tóm tắt

| Bảng | Key | Purpose | Example Query |
|------|-----|---------|---------------|
| **student_study_sessions** | session_id | Track từng session | "Session 1 lasted 20 minutes" |
| **student_daily_study_time** | student + date | Tổng thời gian theo ngày | "Dec 4: 120 minutes total" |
| **student_history_study_time** | student + id_history | Tổng thời gian 1 part | "Reading: 35 minutes (2 sessions)" |
| **student_contest_study_time** | student + id_history_contest | Tổng thời gian toàn bộ contest | "IELTS: 120 minutes (4 parts)" |

---

**4 bảng làm việc cùng nhau để cung cấp cái nhìn toàn diện về thời gian học!**

