
import React, { useState, useRef, useEffect } from 'react';
import ReactDOM from 'react-dom/client';
import { GoogleGenAI, Type } from "@google/genai";

// --- BẮT ĐẦU NỘI DUNG TỪ apiKey.ts ---
// Vui lòng thay thế 'DÁN_KHÓA_API_CỦA_BẠN_VÀO_ĐÂY' bằng khóa API Gemini thực tế của bạn.
// CẢNH BÁO: Không chia sẻ file này hoặc đăng công khai vì nó chứa thông tin nhạy cảm.
const API_KEY = 'AIzaSyBHRAZz8hn1A8rEni--1Cjvtli5STEouVs';

// --- BẮT ĐẦU NỘI DUNG TỪ types.ts ---
export enum Sender {
  User = 'user',
  Bot = 'bot',
}

export interface Message {
  text: string;
  sender: Sender;
}

export enum QuestionType {
  MultipleChoice = 'MC',
  TrueFalse = 'TF',
  ShortAnswer = 'SA',
}

export interface QuizQuestion {
  type: QuestionType;
  question: string;
  options?: string[];
  correctAnswer: string;
  explanation: string;
}

export interface Quiz {
  topic: string;
  questions: QuizQuestion[];
}

export interface UserAnswers {
  [questionIndex: number]: string;
}

export interface QuizResult {
  score: number;
  total: number;
  results: {
    question: string;
    userAnswer: string;
    correctAnswer: string;
    isCorrect: boolean;
    explanation: string;
  }[];
}

export interface Flashcard {
  front: string;
  back: string;
}

export interface FlashcardSet {
    topic: string;
    cards: Flashcard[];
}


// --- BẮT ĐẦU NỘI DUNG TỪ constants.ts ---
const DOCUMENT_CONTENT = `
TRƯỜNG ĐẠI HỌC SƯ PHẠM THÀNH PHỐ HỒ CHÍ MINH
NGUYỄN LÊ ANH
LƯƠNG LÊ HẢI – NGUYỄN MINH HẢI – NGUYỄN VŨ THỤ NHÂN
TOÁN CHO VẬT LÝ
Phần 1
GIẢI TÍCH HÀM MỘT BIẾN VÀ CHUỖI
TÀI LIỆU LƯU HÀNH NỘI BỘ

Lời nói đầu
Cuốn sách Toán cho Vật lý – Phần 1 được biên soạn dành cho sinh viên các ngành Sư
phạm Vật lý, Cử nhân Vật lý, Sư phạm Hóa học và Khoa học Tự nhiên tại Trường Đại
học Sư phạm TP. Hồ Chí Minh. Nội dung tập trung vào các kiến thức toán học nền tảng
với định hướng vận dụng vào lĩnh vực vật lý và khoa học tự nhiên, đặc biệt phù hợp với
nhu cầu của các ngành kỹ thuật. Chúng tôi đã tận dụng nhiều nguồn tài liệu, bao gồm
cả tài liệu quốc tế và trong nước, và kết hợp với kinh nghiệm dày dạn trong giảng dạy và
nghiên cứu của các tác giả để biên soạn nội dung của cuốn sách.
Sách gồm 4 chương: Giới hạn và tính liên tục, Đạo hàm và vi phân, Tích phân, và Lý
thuyết chuỗi. Thay vì đi sâu vào các chứng minh lý thuyết thuần túy, sách ưu tiên trình
bày trực quan, dễ hiểu, gắn liền với các ví dụ và bài tập ứng dụng trong vật lý.
Chúng tôi hy vọng cuốn sách sẽ là công cụ hữu ích giúp sinh viên củng cố kiến thức
và phát triển tư duy toán học trong các bài toán thực tiễn. Tuy chúng tôi đã đặt rất nhiều
công sức và tâm huyết vào cuốn sách này, nhưng không thể tránh khỏi những thiếu sót.
Vì vậy, chúng tôi rất mong nhận được sự góp ý và phản hồi từ bạn đọc.
Chúng tôi xin chân thành cảm ơn Trường Đại học Sư phạm Thành phố Hồ Chí Minh,
Nhà xuất bản Đại học Sư phạm Thành phố Hồ Chí Minh và Ban Chủ nhiệm Khoa Vật
lý đã tạo điều kiện thuận lợi và hỗ trợ quý báu trong quá trình biên soạn cuốn sách này.
Sự đồng hành và khích lệ từ quý đơn vị là nguồn động lực to lớn để chúng tôi hoàn thành
công trình với tinh thần trách nhiệm và tâm huyết.

Mục lục
1 GIỚI HẠN VÀ TÍNH LIÊN TỤC 1
1.1 Bổ túc hàm số . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1 Hàm ngược . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.1.2 Hàm lượng giác ngược . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.1.3 Hàm số hyperbola . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.2 Giới hạn hàm số . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.2.1 Giới hạn hàm số . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.2.2 Các giới hạn cơ bản . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.2.3 Khử dạng vô định . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.2.4 Vô cùng bé và vô cùng lớn . . . . . . . . . . . . . . . . . . . . . . . 44
1.3 Hàm số liên tục . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
1.3.1 Tính liên tục của hàm số . . . . . . . . . . . . . . . . . . . . . . . . 49
1.3.2 Phân loại điểm gián đoạn . . . . . . . . . . . . . . . . . . . . . . . 51
1.3.3 Định lý về hàm liên tục . . . . . . . . . . . . . . . . . . . . . . . . 52
2 ĐẠO HÀM VÀ VI PHÂN 61
2.1 Khả vi, vi phân, đạo hàm và vi phân cấp cao . . . . . . . . . . . . . . . . . 61
2.1.1 Khả vi và vi phân . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.1.2 Vi phân hàm hợp và tính bất biến của dạng vi phân . . . . . . . . 70
2.1.3 Đạo hàm của hàm số cho bởi phương trình tham số . . . . . . . . . 75
2.1.4 Đạo hàm và vi phân cấp cao . . . . . . . . . . . . . . . . . . . . . . 76
2.1.5 Ứng dụng vi phân tính gần đúng . . . . . . . . . . . . . . . . . . . 79
2.2 Đạo hàm và vi phân trong vật lý . . . . . . . . . . . . . . . . . . . . . . . 83
2.3 Đa thức Taylor - Maclaurin . . . . . . . . . . . . . . . . . . . . . . . . . 88
2.3.1 Khai triển Taylor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
2.3.2 Khai triển Maclaurin của các hàm sơ cấp . . . . . . . . . . . . . . . 94
2.3.3 Ứng dụng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
2.4 Quy tắc l’Hospital . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
2.5 Các định lý về giá trị trung bình . . . . . . . . . . . . . . . . . . . . . . . 101
2.6 Khảo sát hàm số cho bởi phương trình tham số . . . . . . . . . . . . . . . 108
2.6.1 Phương trình tham số . . . . . . . . . . . . . . . . . . . . . . . . . 108
2.6.2 Khảo sát đường cong tham số . . . . . . . . . . . . . . . . . . . . . 109
2.6.3 Tọa độ cực . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
3 TÍCH PHÂN 125
3.1 Tích phân bất định . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
3.1.1 Nguyên hàm và tích phân . . . . . . . . . . . . . . . . . . . . . . . 125
3.1.2 Tích phân hàm hữu tỉ . . . . . . . . . . . . . . . . . . . . . . . . . 137
3.1.3 Tích phân hàm vô tỉ . . . . . . . . . . . . . . . . . . . . . . . . . . 145
3.1.4 Tích phân hàm lượng giác . . . . . . . . . . . . . . . . . . . . . . . 155
3.2 Tích phân xác định . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
3.2.1 Các định nghĩa và tính chất . . . . . . . . . . . . . . . . . . . . . . 161
3.2.2 Phương pháp tính . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
3.2.3 Ứng dụng của tích phân xác định . . . . . . . . . . . . . . . . . . . 169
3.2.4 Tích phân suy rộng . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
4 LÝ THUYẾT CHUỖI 209
4.1 Chuỗi số . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
4.1.1 Dãy số . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
4.1.2 Chuỗi số và tính hội tụ . . . . . . . . . . . . . . . . . . . . . . . . . 215
4.1.3 Chuỗi số dương . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
4.1.4 Chuỗi có dấu bất kì . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
4.1.5 Chuỗi kép . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
4.2 Chuỗi lũy thừa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
4.2.1 Chuỗi lũy thừa và bán kính hội tụ . . . . . . . . . . . . . . . . . . . 238
4.2.2 Tính liên tục, đạo hàm và tích phân từng số hạng của chuỗi lũy thừa243
4.2.3 Khai triển hàm thành chuỗi lũy thừa . . . . . . . . . . . . . . . . . 247
4.3 Chuỗi lượng giác, khai triển Fourier . . . . . . . . . . . . . . . . . . . . . . 256
4.3.1 Chuỗi lượng giác . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
4.3.2 Khai triển Fourier hàm tuần hoàn chu kì 2π . . . . . . . . . . . . . 259
4.3.3 Khai triển Fourier hàm tuần hoàn chu kì 2L . . . . . . . . . . . . . 262
4.3.4 Khai triển Fourier trên nửa đoạn [0, π] . . . . . . . . . . . . . . . . 266
4.3.5 Khai triển chuỗi Fourier theo hàm sine hoặc cosine trên đoạn [0, L] 269
4.3.6 Phương trình sóng . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
4.3.7 Hàm mũ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
4.3.8 Các hàm trực giao . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
Tài liệu tham khảo 293
`;

// --- BẮT ĐẦU DỊCH VỤ GEMINI ---
const ai = new GoogleGenAI({ apiKey: API_KEY });

const SYSTEM_INSTRUCTION = `Bạn là gia sư Toán Cao cấp, một trợ lý AI có tên là "Gia sư Toán Cao cấp". Bạn chuyên hỗ trợ sinh viên trong học phần Toán Cao cấp vad dạy học tích hợp STEM ở Đại học. Bạn đóng vai trò là giảng viên giảng dạy học phần Giải tích hàm 1 biến và Giải tích hàm nhiều biến và phương trình vi phân, đồng thời bạn cũng là giáo viên giảng dạy STEM cho sinh viên năm nhất. Bạn sẽ cung cấp các kiến thức của bạn (thông qua các giáo trình mà mình cung cấp cho bạn) để bạn trả lời, hướng dẫn, tạo bài kiểm tra, tạo flashcard môn học để giúp sinh viên tự học các nội dung liên quan. Bạn chỉ trả lời các yêu cầu liên quan đến môn học, không trả lời các câu hỏi ngoài giáo trình mà mình cung cấp cho bạn. Nhiệm vụ của bạn là giúp học sinh hiểu bài, giải bài tập và làm các hoạt động tương tác. Bạn cần tuân thủ các nguyên tắc sau:
1. Phạm vi và hạn chế:
- Chỉ trả lời các yêu cầu liên quan đến môn Toán Cao cấp như đã liệt kê ở trên hoặc liên quan đến kiển thức dạy học STEM.
- Từ chối các yêu cầu nằm ngoài chủ dề học tập.
- Kiến thức nào bạn không nắm vững thì thông báo: "Xin lỗi em, phần này thầy chưa nghiên cứu, chờ thầy nghiên cứu giáo trình nhé".
2. Ngôn ngữ: luôn trả lời bằng tiếng Việt, với giọng văn vui vẻ, thân thiện và dễ gần.
3. Xưng hô:
- Bạn luôn xưng hô là "Thầy" với sinh viên và gọi sinh viên bằng "Em".
- Sinh viên phải xưng hô với Gia sư một cách nghiêm túc, lễ phép bạn sẽ ngừng chat nếu sinh viên xưng hô bất lịch sự, khiếm nhã. Khuyến khích sinh viên xưng hô là "Em" và gọi gia sư bằng "Thầy".
4. Luôn bắt đầu mỗi cuộc trò chuyện bằng câu chào: "Thầy chào em. Thầy là Gia sư Toán Cao cấp. Em muốn học kiến thức mới hay ôn tập kiến thức gì nào?"
5. Phong cách giảng dạy:
- Giải thích các khái niệm Toán học một cách rõ ràng, dễ hiểu.
- Sử dụng các ví dụ minh họa cụ thể để giúp sinh viên nắm vững kiến thức.
- Chủ động liên hệ các khái niệm toán học với các ứng dụng thực tế trong vật lý. Ví dụ, khi thảo luận về đạo hàm, hãy đề cập đến cách nó được sử dụng để tính vận tốc tức thời (v = ds/dt) và gia tốc (a = dv/dt), hoặc cường độ dòng điện (i = dq/dt). Việc này giúp sinh viên thấy rõ mối liên hệ giữa lý thuyết và thực tiễn, làm cho bài học trở nên sinh động và dễ hiểu hơn.
- Có thể tạo các bài kiểm tra ngắn như: Trắc nghiệm (MC) - 4 phương án lựa chọn có 1 phương án đúng; Đúng - Sai (MCA) - 4 phương án lựa chọn có nhiều phương án đúng; Trả lời ngắn (SA) - kết quả được làm tròn đến hàng phần trăm để sinh viên luyện tập.
- Có thể tạo các flashcard hoặc bài tập thực hành để sinh viên củng cố kiến thức.
6. Tương tác và khuyến khích:
- Khuyến khích sinh viên đặt câu hỏi và tương tác tích cực.
- Động viên sinh viên khi họ gặp khó khăn và khen ngợi khi sinh viên tiến bộ.
7. Tạo bài kiểm tra:
- Sau khi giải thích một khái niệm, bạn có thể đề nghị một bài kiểm tra ngắn để giúp sinh viên kiểm tra kiến thức.
- Để làm điều này, hãy kết thúc câu trả lời của bạn bằng thẻ đặc biệt: [SUGGEST_QUIZ]
- Đừng tự tạo câu hỏi kiểm tra trong cuộc trò chuyện thông thường. Chỉ sử dụng thẻ [SUGGEST_QUIZ].
8. Tạo Flashcard:
- Sau khi giải thích một khái niệm, bạn có thể đề nghị tạo flashcard để giúp sinh viên ôn tập.
- Để làm điều này, hãy kết thúc câu trả lời của bạn bằng thẻ đặc biệt: [SUGGEST_FLASHCARDS]
- Đừng tự tạo flashcard trong cuộc trò chuyện thông thường. Chỉ sử dụng thẻ [SUGGEST_FLASHCARDS].`;

async function* streamBotResponse(userQuestion: string): AsyncGenerator<string> {
    const prompt = `
      DỰA VÀO TÀI LIỆU SAU ĐÂY:
      ---
      ${DOCUMENT_CONTENT}
      ---
      CÂU HỎI CỦA NGƯỜI DÙNG: "${userQuestion}"
    `;

    try {
        const responseStream = await ai.models.generateContentStream({
            model: 'gemini-2.5-flash',
            contents: prompt,
            config: {
                systemInstruction: SYSTEM_INSTRUCTION,
                temperature: 0.2,
                topP: 0.8,
                topK: 10,
            },
        });

        for await (const chunk of responseStream) {
            yield chunk.text;
        }
    } catch (error) {
        console.error("Lỗi khi gọi Gemini API:", error);
        if (error instanceof Error) {
            throw new Error(`Đã xảy ra lỗi khi kết nối với trợ lý ảo: ${error.message}`);
        }
        throw new Error("Đã xảy ra lỗi không xác định khi kết nối với trợ lý ảo.");
    }
};

const quizSchema = {
  type: Type.OBJECT,
  properties: {
    topic: {
      type: Type.STRING,
      description: "Chủ đề của bài kiểm tra, ví dụ: 'Đạo hàm và Vi phân'."
    },
    questions: {
      type: Type.ARRAY,
      description: "Một danh sách các câu hỏi.",
      items: {
        type: Type.OBJECT,
        properties: {
          type: {
            type: Type.STRING,
            enum: ['MC', 'SA'],
            description: "Loại câu hỏi: 'MC' cho trắc nghiệm, 'SA' cho trả lời ngắn."
          },
          question: {
            type: Type.STRING,
            description: "Nội dung câu hỏi."
          },
          options: {
            type: Type.ARRAY,
            description: "Danh sách các lựa chọn cho câu hỏi trắc nghiệm (MC). Không áp dụng cho SA.",
            items: { type: Type.STRING }
          },
          correctAnswer: {
            type: Type.STRING,
            description: "Đáp án đúng. Đối với MC, đây là một trong các lựa chọn. Đối với SA, đây là câu trả lời ngắn gọn."
          },
          explanation: {
            type: Type.STRING,
            description: "Giải thích ngắn gọn cho đáp án đúng."
          }
        },
        required: ["type", "question", "correctAnswer", "explanation"]
      }
    }
  },
  required: ["topic", "questions"]
};

async function generateQuiz(conversationHistory: string): Promise<Quiz> {
  const prompt = `
    DỰA VÀO TÀI LIỆU SAU ĐÂY VÀ LỊCH SỬ CUỘC TRÒ CHUYỆN GẦN ĐÂY, hãy tạo một bài kiểm tra ngắn (khoảng 3-5 câu hỏi) để đánh giá sự hiểu biết của sinh viên.
    Bao gồm các câu hỏi trắc nghiệm (MC) và trả lời ngắn (SA).

    TÀI LIỆU:
    ---
    ${DOCUMENT_CONTENT.substring(0, 15000)}
    ---
    LỊCH SỬ CUỘC TRÒ CHUYỆN:
    ---
    ${conversationHistory}
    ---
    
    Hãy tạo một bài kiểm tra tập trung vào các khái niệm vừa được thảo luận.
  `;

  try {
    const response = await ai.models.generateContent({
      model: 'gemini-2.5-flash',
      contents: prompt,
      config: {
        systemInstruction: "Bạn là một trợ lý tạo bài kiểm tra hữu ích, có khả năng tạo ra các câu hỏi dựa trên tài liệu được cung cấp. Hãy tạo ra các câu hỏi phù hợp với trình độ sinh viên đại học.",
        responseMimeType: "application/json",
        responseSchema: quizSchema,
      },
    });

    const jsonText = response.text.trim();
    const quizData = JSON.parse(jsonText);
    return quizData as Quiz;

  } catch (error) {
    console.error("Lỗi khi tạo bài kiểm tra với Gemini API:", error);
    if (error instanceof Error) {
        throw new Error(`Không thể tạo bài kiểm tra: ${error.message}`);
    }
    throw new Error("Đã xảy ra lỗi không xác định khi tạo bài kiểm tra.");
  }
}

const flashcardSchema = {
    type: Type.OBJECT,
    properties: {
        topic: {
            type: Type.STRING,
            description: "Chủ đề của bộ flashcard, ví dụ: 'Các giới hạn cơ bản'."
        },
        cards: {
            type: Type.ARRAY,
            description: "Một danh sách các flashcard.",
            items: {
                type: Type.OBJECT,
                properties: {
                    front: {
                        type: Type.STRING,
                        description: "Mặt trước của thẻ, thường là một câu hỏi hoặc một thuật ngữ."
                    },
                    back: {
                        type: Type.STRING,
                        description: "Mặt sau của thẻ, chứa câu trả lời hoặc định nghĩa."
                    }
                },
                required: ["front", "back"]
            }
        }
    },
    required: ["topic", "cards"]
};


async function generateFlashcards(conversationHistory: string): Promise<FlashcardSet> {
    const prompt = `
    DỰA VÀO TÀI LIỆU VÀ LỊCH SỬ CUỘC TRÒ CHUYỆN GẦN ĐÂY, hãy tạo một bộ flashcard (khoảng 5-8 thẻ) để giúp sinh viên ôn tập.
    Mỗi thẻ nên có một mặt trước (câu hỏi hoặc thuật ngữ) và một mặt sau (câu trả lời hoặc định nghĩa).

    TÀI LIỆU:
    ---
    ${DOCUMENT_CONTENT.substring(0, 15000)}
    ---
    LỊCH SỬ CUỘC TRÒ CHUYỆN:
    ---
    ${conversationHistory}
    ---

    Hãy tạo một bộ flashcard tập trung vào các khái niệm chính vừa được thảo luận.
  `;

    try {
        const response = await ai.models.generateContent({
            model: 'gemini-2.5-flash',
            contents: prompt,
            config: {
                systemInstruction: "Bạn là một trợ lý tạo flashcard hữu ích. Hãy tạo ra các flashcard súc tích, rõ ràng, phù hợp để sinh viên đại học ôn tập nhanh.",
                responseMimeType: "application/json",
                responseSchema: flashcardSchema,
            },
        });

        const jsonText = response.text.trim();
        const flashcardData = JSON.parse(jsonText);
        return flashcardData as FlashcardSet;

    } catch (error) {
        console.error("Lỗi khi tạo flashcard với Gemini API:", error);
        if (error instanceof Error) {
            throw new Error(`Không thể tạo flashcard: ${error.message}`);
        }
        throw new Error("Đã xảy ra lỗi không xác định khi tạo flashcard.");
    }
}


// --- BẮT ĐẦU CÁC THÀNH PHẦN (COMPONENTS) ---

const ChatInput: React.FC<{ onSendMessage: (message: string) => void; isLoading: boolean; }> = ({ onSendMessage, isLoading }) => {
  const [input, setInput] = useState('');

  const handleSubmit = (event: React.FormEvent) => {
    event.preventDefault();
    if (input.trim() && !isLoading) {
      onSendMessage(input);
      setInput('');
    }
  };

  const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (event.key === 'Enter' && !event.shiftKey) {
      event.preventDefault();
      handleSubmit(event as any);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="flex items-center space-x-3">
      <textarea
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyDown={handleKeyDown}
        placeholder="Nhập câu hỏi của bạn ở đây..."
        className="flex-1 p-3 bg-white border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 resize-none transition-shadow duration-200 disabled:opacity-50"
        rows={1}
        disabled={isLoading}
        style={{ maxHeight: '120px' }}
      />
      <button
        type="submit"
        disabled={isLoading || !input.trim()}
        className="bg-teal-600 hover:bg-teal-700 disabled:bg-teal-400 disabled:cursor-not-allowed text-white font-bold p-3 rounded-full transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-white focus:ring-teal-500"
        aria-label="Gửi tin nhắn"
      >
        <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 10l7-7m0 0l7 7m-7-7v18" />
        </svg>
      </button>
    </form>
  );
};

const ChatMessage: React.FC<{ message: Message }> = ({ message }) => {
  const isBot = message.sender === Sender.Bot;

  const userIcon = (
    <div className="w-10 h-10 bg-slate-300 rounded-full flex items-center justify-center flex-shrink-0">
        <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 text-slate-600" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/></svg>
    </div>
  );

  const botIcon = (
    <div className="w-10 h-10 bg-teal-500 rounded-full flex items-center justify-center flex-shrink-0">
        <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/></svg>
    </div>
  );

  return (
    <div className={`flex items-start gap-3 ${isBot ? '' : 'flex-row-reverse'}`}>
      {isBot ? botIcon : userIcon}
      <div className={`max-w-xl p-4 rounded-lg shadow-sm ${isBot ? 'bg-white text-slate-800 border border-slate-200 rounded-tl-none' : 'bg-teal-600 text-white rounded-tr-none'}`}>
        <p className="whitespace-pre-wrap">{message.text}</p>
      </div>
    </div>
  );
};

interface QuizDisplayProps {
  quiz: Quiz;
  userAnswers: UserAnswers;
  quizResult: QuizResult | null;
  onAnswerChange: (questionIndex: number, answer: string) => void;
  onSubmit: () => void;
  onTryAgain: () => void;
}

const QuizDisplay: React.FC<QuizDisplayProps> = ({ quiz, userAnswers, quizResult, onAnswerChange, onSubmit, onTryAgain }) => {
  if (quizResult) {
    return (
      <div className="p-4 md:p-6 bg-white rounded-lg shadow-lg max-w-4xl mx-auto my-8">
        <h2 className="text-2xl font-bold text-center mb-2 text-slate-800">Kết quả bài kiểm tra</h2>
        <p className="text-center text-lg mb-6 font-semibold">
          Điểm của bạn:
          <span className={`ml-2 px-3 py-1 rounded-full text-white ${quizResult.score / quizResult.total >= 0.7 ? 'bg-emerald-600' : 'bg-rose-500'}`}>
            {quizResult.score} / {quizResult.total}
          </span>
        </p>
        <div className="space-y-6">
          {quizResult.results.map((result, index) => (
            <div key={index} className={`p-4 rounded-lg border ${result.isCorrect ? 'border-emerald-300 bg-emerald-50' : 'border-rose-300 bg-rose-50'}`}>
              <p className="font-semibold text-slate-800 mb-2">{index + 1}. {result.question}</p>
              <p className={`text-sm ${result.isCorrect ? 'text-emerald-700' : 'text-rose-700'}`}>
                Câu trả lời của bạn: <span className="font-medium">{result.userAnswer || "Chưa trả lời"}</span>
                {!result.isCorrect && <span className="ml-2 font-medium text-slate-700">(Đáp án đúng: {result.correctAnswer})</span>}
              </p>
               <p className="mt-2 text-sm text-slate-600 border-t border-slate-200 pt-2">
                <span className="font-semibold">Giải thích:</span> {result.explanation}
              </p>
            </div>
          ))}
        </div>
        <div className="mt-8 text-center">
          <button
            onClick={onTryAgain}
            className="bg-teal-600 hover:bg-teal-700 text-white font-bold py-2 px-6 rounded-lg transition-colors"
          >
            Làm lại
          </button>
        </div>
      </div>
    );
  }

  return (
    <div className="p-4 md:p-6 bg-white rounded-lg shadow-lg max-w-4xl mx-auto my-8">
      <h2 className="text-2xl font-bold text-center mb-1 text-slate-800">{quiz.topic}</h2>
      <p className="text-center text-slate-500 mb-6">Hãy chọn câu trả lời đúng nhất cho các câu hỏi dưới đây.</p>
      <form onSubmit={(e) => { e.preventDefault(); onSubmit(); }} className="space-y-8">
        {quiz.questions.map((q, index) => (
          <div key={index} className="border-t border-slate-200 pt-6">
            <fieldset>
              <legend className="font-semibold text-lg mb-3 text-slate-800">{`Câu ${index + 1}: ${q.question}`}</legend>
              {q.type === 'MC' && q.options && (
                <div className="space-y-3">
                  {q.options.map((option, optionIndex) => (
                    <label key={optionIndex} className="flex items-center p-3 rounded-lg border border-slate-200 hover:bg-slate-50 cursor-pointer transition-colors">
                      <input
                        type="radio"
                        name={`question-${index}`}
                        value={option}
                        checked={userAnswers[index] === option}
                        onChange={(e) => onAnswerChange(index, e.target.value)}
                        className="h-4 w-4 text-teal-600 focus:ring-teal-500 border-slate-300"
                      />
                      <span className="ml-3 text-slate-700">{option}</span>
                    </label>
                  ))}
                </div>
              )}
              {q.type === 'SA' && (
                 <input
                    type="text"
                    value={userAnswers[index] || ''}
                    onChange={(e) => onAnswerChange(index, e.target.value)}
                    placeholder="Nhập câu trả lời của bạn..."
                    className="mt-2 block w-full p-2 border border-slate-300 rounded-md shadow-sm focus:ring-teal-500 focus:border-teal-500 sm:text-sm"
                 />
              )}
            </fieldset>
          </div>
        ))}
        <div className="pt-6 text-center">
          <button
            type="submit"
            className="bg-emerald-600 hover:bg-emerald-700 text-white font-bold py-3 px-8 rounded-lg transition-colors text-lg"
          >
            Nộp bài
          </button>
        </div>
      </form>
    </div>
  );
};

interface FlashcardDisplayProps {
  flashcardSet: FlashcardSet;
  onExit: () => void;
}

const FlashcardDisplay: React.FC<FlashcardDisplayProps> = ({ flashcardSet, onExit }) => {
    const [currentCardIndex, setCurrentCardIndex] = useState(0);
    const [isFlipped, setIsFlipped] = useState(false);
    
    const card = flashcardSet.cards[currentCardIndex];

    const handleNext = () => {
        if (currentCardIndex < flashcardSet.cards.length - 1) {
            setIsFlipped(false);
            setCurrentCardIndex(currentCardIndex + 1);
        }
    };
    
    const handlePrev = () => {
        if (currentCardIndex > 0) {
            setIsFlipped(false);
            setCurrentCardIndex(currentCardIndex - 1);
        }
    };

    const cardContainerStyle: React.CSSProperties = {
        perspective: '1000px',
    };

    const cardInnerStyle: React.CSSProperties = {
        transformStyle: 'preserve-3d',
        transition: 'transform 0.6s',
        transform: isFlipped ? 'rotateY(180deg)' : 'none',
    };

    const cardFaceStyle: React.CSSProperties = {
        backfaceVisibility: 'hidden',
        WebkitBackfaceVisibility: 'hidden', 
    };

    const cardBackStyle: React.CSSProperties = {
        ...cardFaceStyle,
        transform: 'rotateY(180deg)',
    };

    return (
        <div className="p-4 md:p-6 max-w-4xl w-full mx-auto my-8 flex flex-col items-center">
            <div className="w-full relative">
                 <button 
                    onClick={onExit}
                    className="absolute top-0 right-0 bg-slate-200 hover:bg-rose-500 text-slate-800 hover:text-white font-bold py-2 px-4 rounded-lg transition-colors z-10"
                    aria-label="Thoát Flashcards"
                >
                    Thoát
                </button>
                <h2 className="text-2xl font-bold text-center mb-2 text-slate-800">{flashcardSet.topic}</h2>
                <p className="text-center text-slate-500 mb-6">
                    Thẻ {currentCardIndex + 1} / {flashcardSet.cards.length}
                </p>
            </div>
           
            <div 
                className="w-full max-w-xl h-80 cursor-pointer" 
                onClick={() => setIsFlipped(!isFlipped)}
                style={cardContainerStyle}
                aria-live="polite"
            >
                <div className="relative w-full h-full" style={cardInnerStyle}>
                    {/* Card Front */}
                    <div className="absolute w-full h-full p-6 flex items-center justify-center bg-white border border-slate-200 rounded-lg shadow-lg text-center" style={cardFaceStyle}>
                        <p className="text-2xl font-semibold text-slate-800">{card.front}</p>
                    </div>
                    {/* Card Back */}
                    <div className="absolute w-full h-full p-6 flex items-center justify-center bg-teal-50 border border-teal-200 rounded-lg shadow-lg text-center" style={cardBackStyle}>
                        <p className="text-lg text-slate-700 whitespace-pre-wrap">{card.back}</p>
                    </div>
                </div>
            </div>

            <div className="mt-8 flex justify-between w-full max-w-xl">
                <button
                    onClick={handlePrev}
                    disabled={currentCardIndex === 0}
                    className="bg-teal-600 hover:bg-teal-700 disabled:bg-teal-300 text-white font-bold py-2 px-6 rounded-lg transition-colors"
                >
                    Trước
                </button>
                <button
                    onClick={() => setIsFlipped(!isFlipped)}
                    className="bg-slate-600 hover:bg-slate-700 text-white font-bold py-2 px-6 rounded-lg transition-colors"
                >
                    Lật thẻ
                </button>
                <button
                    onClick={handleNext}
                    disabled={currentCardIndex === flashcardSet.cards.length - 1}
                    className="bg-teal-600 hover:bg-teal-700 disabled:bg-teal-300 text-white font-bold py-2 px-6 rounded-lg transition-colors"
                >
                    Sau
                </button>
            </div>
        </div>
    );
};


const Instructions: React.FC = () => {
  const [isOpen, setIsOpen] = useState(false);

  const toggleInstructions = () => {
    setIsOpen(!isOpen);
  };

  return (
    <div className="mx-auto w-full max-w-4xl px-4 md:px-6 pt-4">
      <div className="border border-slate-200 bg-white rounded-lg shadow-sm">
        <h2>
          <button
            type="button"
            onClick={toggleInstructions}
            className="flex items-center justify-between w-full p-4 font-semibold text-left text-slate-700 hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-teal-300"
            aria-expanded={isOpen}
            aria-controls="instructions-content"
          >
            <span>Hướng dẫn sử dụng</span>
            <svg
              className={`w-5 h-5 transform transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`}
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
            >
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7" />
            </svg>
          </button>
        </h2>
        <div
          id="instructions-content"
          className={`overflow-hidden transition-all duration-300 ease-in-out ${isOpen ? 'max-h-96' : 'max-h-0'}`}
        >
          <div className="p-4 border-t border-slate-200 text-slate-600">
            <p className="font-bold mb-2">Chào mừng bạn đến với Gia sư Toán Cao cấp!</p>
            <ul className="list-disc list-inside space-y-2">
              <li>
                <strong>Đặt câu hỏi học tập:</strong> Nhập bất kỳ câu hỏi nào liên quan đến nội dung môn học Giải tích vào ô chat và nhấn gửi.
              </li>
              <li>
                <strong>Tương tác với Gia sư AI:</strong> Gia sư ('Thầy') sẽ trả lời, giải thích các khái niệm và cung cấp ví dụ dựa trên tài liệu học tập.
              </li>
              <li>
                <strong>Làm bài kiểm tra & Flashcards:</strong> Sau khi thảo luận về một chủ đề, 'Thầy' có thể đề xuất một bài kiểm tra hoặc một bộ flashcard. Nhấn vào các nút gợi ý để bắt đầu.
              </li>
               <li>
                <strong>Thoát khỏi chế độ học tập:</strong> Bạn có thể thoát bài kiểm tra hoặc flashcard bất cứ lúc nào bằng cách nhấn nút 'Thoát' hoặc chỉ cần gửi một tin nhắn mới.
              </li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  );
};

const PhysicsApplications: React.FC = () => {
  const [isOpen, setIsOpen] = useState(false);

  const toggleSection = () => {
    setIsOpen(!isOpen);
  };

  return (
    <div className="mx-auto w-full max-w-4xl px-4 md:px-6 pt-4">
      <div className="border border-slate-200 bg-white rounded-lg shadow-sm">
        <h2>
          <button
            type="button"
            onClick={toggleSection}
            className="flex items-center justify-between w-full p-4 font-semibold text-left text-slate-700 hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-teal-300"
            aria-expanded={isOpen}
            aria-controls="physics-apps-content"
          >
            <span>Ứng dụng Giải tích trong Vật lý</span>
            <svg
              className={`w-5 h-5 transform transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`}
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
            >
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7" />
            </svg>
          </button>
        </h2>
        <div
          id="physics-apps-content"
          className={`overflow-hidden transition-all duration-300 ease-in-out ${isOpen ? 'max-h-[500px]' : 'max-h-0'}`}
        >
          <div className="p-4 border-t border-slate-200 text-slate-600">
            <p className="mb-4">
              Giải tích, đặc biệt là đạo hàm và vi phân, là công cụ toán học nền tảng để mô tả và phân tích các hiện tượng vật lý. Dưới đây là một số ví dụ điển hình:
            </p>
            <ul className="list-disc list-inside space-y-3">
              <li>
                <strong>Vận tốc và Gia tốc:</strong> Trong chuyển động học, nếu một vật có phương trình chuyển động là \`s(t)\`, thì vận tốc tức thời \`v(t)\` là đạo hàm của quãng đường theo thời gian, và gia tốc tức thời \`a(t)\` là đạo hàm của vận tốc.
                <div className="mt-2 ml-4 p-2 bg-slate-100 rounded text-sm text-slate-800 font-mono">
                  <p>v(t) = s'(t) = ds/dt</p>
                  <p>a(t) = v'(t) = s''(t) = d²s/dt²</p>
                </div>
              </li>
              <li>
                <strong>Tốc độ thay đổi:</strong> Đạo hàm biểu thị tốc độ thay đổi của một đại lượng này so với một đại lượng khác. Ví dụ, tốc độ thay đổi của thể tích nước trong một bể chứa theo thời gian, hoặc tốc độ thay đổi của nhiệt độ trong một thanh kim loại.
              </li>
              <li>
                <strong>Cường độ dòng điện:</strong> Trong mạch điện, cường độ dòng điện tức thời \`i(t)\` được định nghĩa là tốc độ thay đổi của điện lượng \`q(t)\` qua một tiết diện của dây dẫn.
                 <div className="mt-2 ml-4 p-2 bg-slate-100 rounded text-sm text-slate-800 font-mono">
                  <p>i(t) = q'(t) = dq/dt</p>
                </div>
              </li>
               <li>
                <strong>Lực và Công:</strong> Các khái niệm như lực, công, và năng lượng trong cơ học thường được mô tả bằng các phương trình vi phân và tích phân, bắt nguồn từ các định luật của Newton.
              </li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  );
};

// --- THÀNH PHẦN APP CHÍNH ---
const QUIZ_SUGGESTION_TAG = '[SUGGEST_QUIZ]';
const FLASHCARD_SUGGESTION_TAG = '[SUGGEST_FLASHCARDS]';


function App() {
  const [messages, setMessages] = useState<Message[]>([
    {
      text: 'Thầy chào em. Thầy là Gia sư Toán Cao cấp. Em muốn học kiến thức mới hay ôn tập kiến thức gì nào?',
      sender: Sender.Bot,
    },
  ]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const messagesEndRef = useRef<HTMLDivElement>(null);

  // Quiz state
  const [quiz, setQuiz] = useState<Quiz | null>(null);
  const [userAnswers, setUserAnswers] = useState<UserAnswers>({});
  const [quizResult, setQuizResult] = useState<QuizResult | null>(null);
  const [isQuizMode, setIsQuizMode] = useState(false);

  // Flashcard state
  const [flashcardSet, setFlashcardSet] = useState<FlashcardSet | null>(null);
  const [isFlashcardMode, setIsFlashcardMode] = useState(false);


  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  };

  useEffect(() => {
    if (!isQuizMode && !isFlashcardMode) {
      scrollToBottom();
    }
  }, [messages, isQuizMode, isFlashcardMode]);

  const handleSendMessage = async (userMessage: string) => {
    if (!userMessage.trim() || isLoading) return;
    
    // Exit any active mode if user sends a message
    if (isQuizMode || isFlashcardMode) {
        setIsQuizMode(false);
        setQuiz(null);
        setQuizResult(null);
        setUserAnswers({});
        setIsFlashcardMode(false);
        setFlashcardSet(null);
    }

    setError(null);
    const newUserMessage: Message = { text: userMessage, sender: Sender.User };
    setMessages((prevMessages) => [
      ...prevMessages, 
      newUserMessage,
      { text: '', sender: Sender.Bot } // Placeholder for bot response
    ]);
    setIsLoading(true);

    try {
      const stream = streamBotResponse(userMessage);
      let botResponseText = '';
      for await (const chunk of stream) {
        botResponseText += chunk;
        setMessages((prevMessages) => {
          const updatedMessages = [...prevMessages];
          updatedMessages[updatedMessages.length - 1] = {
            ...updatedMessages[updatedMessages.length - 1],
            text: botResponseText,
          };
          return updatedMessages;
        });
      }
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Đã xảy ra lỗi không xác định. Vui lòng thử lại.';
      setError(errorMessage);
       setMessages((prevMessages) => {
        const updatedMessages = [...prevMessages.slice(0, -1)];
        updatedMessages.push({ text: `Lỗi: ${errorMessage}`, sender: Sender.Bot });
        return updatedMessages;
      });
    } finally {
      setIsLoading(false);
    }
  };
  
  // --- Quiz Functions ---
  const handleRequestQuiz = async () => {
    setIsLoading(true);
    setError(null);
    setMessages(prev => [...prev, { text: "Tuyệt vời! Để thầy chuẩn bị một vài câu hỏi cho em nhé...", sender: Sender.Bot }]);

    try {
        const conversationHistory = messages.map(m => `${m.sender}: ${m.text}`).join('\n');
        const quizData = await generateQuiz(conversationHistory);
        setQuiz(quizData);
        setIsQuizMode(true);
        setUserAnswers({});
        setQuizResult(null);
    } catch (err) {
        const errorMessage = err instanceof Error ? err.message : 'Đã xảy ra lỗi không xác định.';
        setError(errorMessage);
        setMessages(prev => [...prev, { text: `Lỗi khi tạo bài kiểm tra: ${errorMessage}`, sender: Sender.Bot }]);
    } finally {
        setIsLoading(false);
    }
  };

  const handleAnswerChange = (questionIndex: number, answer: string) => {
    setUserAnswers(prev => ({ ...prev, [questionIndex]: answer }));
  };

  const handleSubmitQuiz = () => {
    if (!quiz) return;
    
    let score = 0;
    const results = quiz.questions.map((q, index) => {
        const userAnswer = userAnswers[index] || "";
        const isCorrect = userAnswer.trim().toLowerCase() === String(q.correctAnswer).trim().toLowerCase();

        if (isCorrect) {
            score++;
        }
        return {
            question: q.question,
            userAnswer,
            correctAnswer: q.correctAnswer,
            isCorrect,
            explanation: q.explanation,
        };
    });

    setQuizResult({
        score,
        total: quiz.questions.length,
        results,
    });
    window.scrollTo(0, 0);
  };
  
  const handleTryAgain = () => {
    setUserAnswers({});
    setQuizResult(null);
  };
  
  const handleExitQuiz = () => {
    setIsQuizMode(false);
    setQuiz(null);
    setQuizResult(null);
    setUserAnswers({});
    setMessages(prev => [...prev, {text: "Được rồi, chúng ta hãy tiếp tục học nhé. Em có câu hỏi nào khác không?", sender: Sender.Bot}])
  }

  // --- Flashcard Functions ---
  const handleRequestFlashcards = async () => {
      setIsLoading(true);
      setError(null);
      setMessages(prev => [...prev, { text: "Hay lắm! Để thầy soạn vài tấm thẻ ghi nhớ cho em ôn bài nhé...", sender: Sender.Bot }]);

      try {
          const conversationHistory = messages.map(m => `${m.sender}: ${m.text}`).join('\n');
          const flashcardData = await generateFlashcards(conversationHistory);
          setFlashcardSet(flashcardData);
          setIsFlashcardMode(true);
      } catch (err) {
          const errorMessage = err instanceof Error ? err.message : 'Đã xảy ra lỗi không xác định.';
          setError(errorMessage);
          setMessages(prev => [...prev, { text: `Lỗi khi tạo flashcard: ${errorMessage}`, sender: Sender.Bot }]);
      } finally {
          setIsLoading(false);
      }
  };

  const handleExitFlashcards = () => {
      setIsFlashcardMode(false);
      setFlashcardSet(null);
      setMessages(prev => [...prev, {text: "Tốt lắm! Em có muốn tiếp tục thảo luận về chủ đề này không?", sender: Sender.Bot}]);
  };

  const lastBotMessage = messages.filter(m => m.sender === Sender.Bot).pop();
  const showQuizSuggestion = !isLoading && lastBotMessage?.text.includes(QUIZ_SUGGESTION_TAG);
  const showFlashcardSuggestion = !isLoading && lastBotMessage?.text.includes(FLASHCARD_SUGGESTION_TAG);

  const renderContent = () => {
    if (isFlashcardMode && flashcardSet) {
        return <FlashcardDisplay flashcardSet={flashcardSet} onExit={handleExitFlashcards} />;
    }

    if (isQuizMode && quiz) {
        return (
            <div className="relative">
                <div className="absolute top-4 right-4 z-10">
                    <button 
                        onClick={handleExitQuiz}
                        className="bg-slate-200 hover:bg-rose-500 text-slate-800 hover:text-white font-bold py-2 px-4 rounded-lg transition-colors"
                        aria-label="Thoát kiểm tra"
                    >
                        Thoát
                    </button>
                </div>
                <QuizDisplay 
                    quiz={quiz} 
                    userAnswers={userAnswers}
                    quizResult={quizResult}
                    onAnswerChange={handleAnswerChange}
                    onSubmit={handleSubmitQuiz}
                    onTryAgain={handleTryAgain}
                />
            </div>
        )
    }
    
    return (
        <div className="p-4 md:p-6 space-y-6">
            {messages.map((msg, index) => (
              <ChatMessage 
                key={index} 
                message={{
                    ...msg,
                    text: msg.text
                        .replace(QUIZ_SUGGESTION_TAG, '')
                        .replace(FLASHCARD_SUGGESTION_TAG, '')
                        .trim()
                }} 
              />
            ))}
            {(showQuizSuggestion || showFlashcardSuggestion) && (
                <div className="flex justify-center items-center my-4 space-x-4">
                    {showQuizSuggestion && (
                        <button
                            onClick={handleRequestQuiz}
                            className="bg-amber-500 hover:bg-amber-600 text-white font-bold py-2 px-6 rounded-lg transition-colors duration-200 animate-pulse"
                        >
                            Làm bài kiểm tra nhanh!
                        </button>
                    )}
                    {showFlashcardSuggestion && (
                         <button
                            onClick={handleRequestFlashcards}
                            className="bg-sky-500 hover:bg-sky-600 text-white font-bold py-2 px-6 rounded-lg transition-colors duration-200 animate-pulse"
                        >
                            Tạo Flashcards
                        </button>
                    )}
                </div>
            )}
             {error && (
                <div className="bg-rose-100 border border-rose-400 text-rose-700 px-4 py-3 rounded-lg relative" role="alert">
                    <strong className="font-bold">Lỗi! </strong>
                    <span className="block sm:inline">{error}</span>
                </div>
            )}
            <div ref={messagesEndRef} />
        </div>
    )
  }

  return (
    <div className="flex flex-col h-screen bg-slate-50 text-slate-900 font-sans">
      <header className="bg-white shadow-sm p-4 text-center border-b border-slate-200">
        <h1 className="text-2xl font-bold tracking-wider text-slate-800">
          Chat bot AI - Gia sư Toán Cao cấp
        </h1>
        <p className="text-sm text-slate-600">Trợ lý Giải tích Hàm một biến</p>
      </header>

      <Instructions />
      <PhysicsApplications />

      <main className="flex-1 overflow-y-auto relative">
        {renderContent()}
      </main>

      <footer className={`bg-white p-4 transition-opacity duration-300 border-t border-slate-200 ${isQuizMode || isFlashcardMode ? 'opacity-0 pointer-events-none' : 'opacity-100'}`}>
        <ChatInput onSendMessage={handleSendMessage} isLoading={isLoading} />
        <p className="text-center text-xs text-slate-500 mt-4">
          © 09/2025 - Thiết kế bởi: Thụ Nhân (với sự hỗ trợ của Google AI Studio - Liên hệ: nhannvt@hcmue.edu.vn)
        </p>
      </footer>
    </div>
  );
}


// --- ĐIỂM KHỞI ĐỘNG ỨNG DỤNG ---
const rootElement = document.getElementById('root');
if (!rootElement) {
  throw new Error("Không tìm thấy phần tử root để gắn kết.");
}

const root = ReactDOM.createRoot(rootElement);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);