/**
 * Cross-portal: patient books -> doctor sees the appointment.
 *
 * This is the journey that exercises the whole stack:
 *   1. Patient API-logs in, queries availability, picks the first open slot
 *      for the seeded cardiologist, and POSTs a booking.
 *   2. Backend persists the appointment, emits a notification, and would
 *      schedule reminders.
 *   3. We open the doctor portal in a real browser, log in, and assert the
 *      newly-booked appointment shows up on their dashboard.
 *
 * The booking is done via API rather than UI on purpose: we already cover
 * patient UI route smoke, and the time-picker surface changes often. The
 * API-side test covers the cross-portal contract.
 */
import { test, expect, request as apiRequest } from '@playwright/test';
import { API_URL, PORTALS, USERS } from '../../fixtures/users';

interface DaySlots {
  date: string;
  dayOfWeek: number;
  slots: { startAt: string; endAt: string; available: boolean }[];
}

interface AvailabilityResponse {
  doctorTimezone: string;
  patientTimezone: string;
  slots: DaySlots[];
}

test('patient books with seeded doctor -> doctor portal surfaces it', async ({ page }) => {
  const ctx = await apiRequest.newContext();
  let patientAccessToken: string | undefined;
  let patientRefreshToken: string | undefined;

  try {
    // ---------- patient logs in via API ----------
    const loginRes = await ctx.post(`${API_URL}/api/v2/auth/login`, {
      data: { email: USERS.patient.email, password: USERS.patient.password },
    });
    expect(loginRes.ok(), 'patient login should succeed').toBeTruthy();
    const loginBody = await loginRes.json();
    patientAccessToken = loginBody.accessToken;
    patientRefreshToken = loginBody.refreshToken;

    // ---------- look up the seeded doctor id ----------
    const doctorsRes = await ctx.get(`${API_URL}/api/v2/doctors?specialty=cardiology`, {
      headers: { Authorization: `Bearer ${patientAccessToken}` },
    });
    expect(doctorsRes.ok()).toBeTruthy();
    // Browse endpoint returns DoctorCard[] (see doctors.service.ts).
    const doctors = (await doctorsRes.json()) as { id: string; fullName: string }[];
    const doctor = doctors.find((d) => /imran/i.test(d.fullName));
    expect(doctor, 'seeded cardiologist should be in the directory').toBeTruthy();

    // ---------- pick the next available slot ----------
    const availRes = await ctx.get(`${API_URL}/api/v2/appointments/availability/${doctor!.id}?days=14`, {
      headers: { Authorization: `Bearer ${patientAccessToken}` },
    });
    expect(availRes.ok()).toBeTruthy();
    const availability = (await availRes.json()) as AvailabilityResponse | DaySlots[];
    const days = Array.isArray(availability) ? availability : availability.slots;
    expect(days.length, 'availability should include at least one day').toBeGreaterThan(0);
    const slot = days.flatMap((d) => d.slots).find((s) => s.available);
    expect(slot, 'doctor should have at least one open slot in the next 2 weeks').toBeTruthy();

    // ---------- book ----------
    const bookRes = await ctx.post(`${API_URL}/api/v2/appointments`, {
      headers: { Authorization: `Bearer ${patientAccessToken}`, 'Content-Type': 'application/json' },
      data: {
        doctorId: doctor!.id,
        specialtyName: 'cardiology',
        scheduledAt: slot!.startAt,
        symptoms: 'E2E test booking - palpitations for 2 days',
        urgency: 'routine',
      },
    });
    const bookingBody = await bookRes.text();
    expect(
      bookRes.ok(),
      `booking should succeed (got ${bookRes.status()}): ${bookingBody}`,
    ).toBeTruthy();
    const appointment = JSON.parse(bookingBody);
    expect(appointment).toHaveProperty('id');
    expect(appointment.status).toMatch(/pending|scheduled|confirmed/i);

    // ---------- doctor logs in (UI) and sees the booking ----------
    await page.goto(`${PORTALS.doctor}/login`);
    await page.getByRole('textbox', { name: 'Email' }).fill(USERS.doctor.email);
    await page.getByRole('textbox', { name: 'Password' }).fill(USERS.doctor.password);
    await page.getByRole('button', { name: /sign in/i }).click();
    await page.waitForURL(/\/dashboard$/, { timeout: 15_000 });

    // The current dashboard surfaces booked consults in the queue table.
    const appointmentRow = page
      .getByRole('row', {
        name: /Ayesha Siddiqui.*Cardiology.*E2E test booking.*Pending/i,
      })
      .first();
    await expect(appointmentRow).toBeVisible({ timeout: 15_000 });
  } finally {
    await Promise.allSettled([
      patientAccessToken && patientRefreshToken
        ? ctx.post(`${API_URL}/api/v2/auth/logout`, {
            headers: {
              Authorization: `Bearer ${patientAccessToken}`,
              'Content-Type': 'application/json',
            },
            data: { refreshToken: patientRefreshToken },
          })
        : Promise.resolve(),
      page.request.post(`${PORTALS.doctor}/api/auth/logout`),
    ]);

    await ctx.dispose();
  }
});
