# Patient Authentication and Profile Claiming Flow

This document outlines the different methods for patient authentication, including standard sign-up, anonymous user conversion, and the process for claiming a pre-existing patient profile created by a clinic administrator.

---

## 1. Standard Patient Sign-Up

A new user can register directly as a patient. This flow creates a new `User` record in Firebase Authentication and Firestore, along with a corresponding `PatientProfile`.

### Flow:

1.  The client application calls the `AuthService.signUp` method with the user's email and password.
2.  The system creates a new Firebase user.
3.  A new `User` document and a `PatientProfile` document are created and linked together.

### Example:

```typescript
// In your client-side code
import { authService } from "./services"; // Assuming you have an initialized authService

async function registerPatient(email, password) {
  try {
    const user = await authService.signUp(email, password, UserRole.PATIENT);
    console.log("Patient registered successfully:", user);
  } catch (error) {
    console.error("Registration failed:", error);
  }
}
```

A similar flow exists for social providers like Google using `signInWithGoogle`.

---

## 2. Standard Patient Sign-In

Existing users can sign in using their credentials.

### Flow:

1.  The client application calls `AuthService.signIn` with the user's email and password.
2.  Firebase authenticates the user.
3.  The application receives the user's profile data.

### Example:

```typescript
// In your client-side code
async function loginPatient(email, password) {
  try {
    const user = await authService.signIn(email, password);
    console.log("Patient signed in successfully:", user);
  } catch (error) {
    console.error("Sign-in failed:", error);
  }
}
```

---

## 3. Anonymous User Flow

Users can start using the application without creating a full account. They are assigned an anonymous user profile which can be converted to a permanent account later.

### Flow:

1.  **Initial Anonymous Sign-In:** The client calls `AuthService.signInAnonymously()`. This creates an anonymous Firebase user and a corresponding `User` and `PatientProfile` in Firestore.
2.  **Upgrading the Account:** When the user decides to create a permanent account, the client calls one of the upgrade methods, such as `AuthService.upgradeAnonymousUser(email, password)`.
3.  The anonymous account is linked to the new credentials (e.g., email/password). The `isAnonymous` flag on the `User` document is set to `false`. The existing `PatientProfile` is retained.

---

## 4. Claiming a Manually Created Profile

This flow is for patients whose profiles are created in advance by a clinic administrator. This allows clinics to manage patient records before the patient has registered on the platform.

### Step 1: Admin Creates Profile and Invite Token

1.  **Create Manual Patient:** A clinic admin uses `PatientService.createManualPatient()` to create a patient profile. This profile is not linked to any user (`userRef` is empty) and is marked with `isManual: true`.
2.  **Create Invite Token:** The admin then calls `PatientService.createPatientToken()` for the newly created patient. This generates a unique, short-lived token and stores it in the `inviteTokens` subcollection of the patient's profile.
3.  **Send Invitation:** The token is sent to the patient (e.g., via email). This is typically handled by a Cloud Function that triggers when a new token is created.

### Example (Admin Action):

```typescript
// In an admin panel or backend service
import { patientService } from "./services";

async function invitePatient(patientData, adminId) {
  // 1. Create the manual patient profile
  const manualProfile = await patientService.createManualPatient(patientData, {
    id: adminId,
    role: "clinic_admin",
    associatedClinicId: patientData.clinicId,
  });

  // 2. Create an invitation token for the new profile
  const tokenData = {
    patientId: manualProfile.id,
    clinicId: patientData.clinicId,
    email: patientData.email,
  };
  const inviteToken = await patientService.createPatientToken(
    tokenData,
    adminId
  );

  console.log(`Invite token created: ${inviteToken.token}`);
  // (An automated process would now email this token to the patient)
}
```

### Step 2: Patient Signs Up with the Invite Token

The patient uses the standard sign-up flow but includes the invitation token.

1.  **Sign-Up with Token:** The patient goes to the registration page and signs up using email/password (`AuthService.signUp`) or a social provider (`AuthService.signInWithGoogle`). They provide the `patientInviteToken` they received.
2.  **Profile Claiming:**
    - The system validates the token.
    - If valid, it finds the corresponding `PatientProfile` that was manually created.
    - It links the new `User` account to this existing `PatientProfile` by setting the `userRef`.
    - It updates the profile's `isManual` flag to `false`.
    - The invitation token is marked as `USED`.

### Example (Patient Action):

```typescript
// In your client-side code during registration
import { authService } from "./services";

async function registerAndClaimProfile(email, password, inviteToken) {
  try {
    const user = await authService.signUp(email, password, UserRole.PATIENT, {
      patientInviteToken: inviteToken,
    });
    console.log("Successfully registered and claimed profile:", user);
  } catch (error) {
    console.error("Claiming profile failed:", error);
  }
}
```

---

## 5. Retrieving Invite Tokens (For Admins)

Clinic administrators can retrieve a list of all active, unexpired invitation tokens for their clinic. This is useful for assisting patients in person who may not have access to their email.

### Flow:

1.  An authenticated clinic administrator makes a request to an endpoint that calls `PatientService.getActiveInviteTokensByClinic(clinicId)`.
2.  The service performs a secure query to find all tokens associated with the admin's clinic that are currently active.
3.  The list of tokens is returned to the admin.

### Example (Admin Action):

```typescript
// In a secure admin-only part of the application
import { patientService } from "./services";

async function fetchActiveTokens(clinicId) {
  try {
    // The backend must verify that the user is an admin for this clinicId
    const tokens = await patientService.getActiveInviteTokensByClinic(clinicId);
    console.log("Active tokens for the clinic:", tokens);
    // The admin can now read the token to the patient
  } catch (error) {
    console.error("Failed to fetch tokens:", error);
  }
}
```

Admins can also retrieve tokens for a specific patient.

### Example (Admin Action for a specific patient):

```typescript
// In a secure admin-only part of the application
import { patientService } from "./services";

async function fetchTokensForPatient(patientId) {
  try {
    // The backend must verify that the user is an admin and has
    // permission to view this patient's details.
    const tokens = await patientService.getActiveInviteTokensByPatient(
      patientId
    );
    console.log(`Active tokens for patient ${patientId}:`, tokens);
  } catch (error) {
    console.error("Failed to fetch tokens for patient:", error);
  }
}
```

This ensures a seamless experience where the patient's pre-existing data is automatically linked to their new account.
