import { test, expect, type Page } from '@playwright/test';

const API_BASE = 'http://localhost:3000';

function unwrapData<T>(payload: unknown): T {
  let current: unknown = payload;

  while (current && typeof current === 'object' && 'data' in current) {
    current = (current as { data: unknown }).data;
  }

  return current as T;
}

async function login(page: Page) {
  await page.goto('/login');
  await page.fill('input[type="email"]', 'superuser@headroom.test');
  await page.fill('input[type="password"]', 'password');
  await page.click('button[type="submit"]');
  await page.waitForURL('/dashboard');
}

async function createTeamMember(page: Page, token: string) {
  const response = await page.request.post(`${API_BASE}/api/team-members`, {
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    data: {
      name: `Capacity Calendar Tester ${Date.now()}`,
      role_id: 1,
      hourly_rate: 150,
      active: true
    }
  });

  const body = unwrapData<{ id: string }>(await response.json());
  return body.id;
}

async function createPto(page: Page, token: string, memberId: string, date: string) {
  await page.request.post(`${API_BASE}/api/ptos`, {
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    data: {
      team_member_id: memberId,
      start_date: date,
      end_date: date,
      reason: 'Capacity calendar PTO test'
    }
  });
}

async function expectNoRawErrorAlerts(page: Page) {
  await expect(page.locator('.alert.alert-error:has-text("<!DOCTYPE")')).toHaveCount(0);
  await expect(page.locator('.alert.alert-error:has-text("SQLSTATE")')).toHaveCount(0);
}

test.describe('Capacity Calendar', () => {
  let authToken: string;
  let memberId: string | null = null;

  test.beforeEach(async ({ page }) => {
    await login(page);
    const token = (await page.evaluate(() => localStorage.getItem('headroom_access_token'))) ?? '';
    authToken = token;
    memberId = await createTeamMember(page, authToken);

    await page.goto('/capacity');
    await page.waitForURL('/capacity');
    await page.waitForResponse((response) => response.url().includes('/api/team-members') && response.status() === 200);
  });

  test.afterEach(async ({ page }) => {
    if (memberId) {
      await page.request.delete(`${API_BASE}/api/team-members/${memberId}`, {
        headers: { Authorization: `Bearer ${authToken}` }
      }).catch(() => null);
      memberId = null;
    }
  });

  test('should save availability change with success message', async ({ page }) => {
    await expect(page.locator('select[aria-label="Select team member"]')).toBeVisible({ timeout: 10000 });
    await expectNoRawErrorAlerts(page);

    const teamMemberSelect = page.locator('select[aria-label="Select team member"]');
    if (memberId) {
      await teamMemberSelect.selectOption({ value: memberId });
    }

    await expect(page.locator('[data-testid="capacity-calendar"]')).toBeVisible({ timeout: 10000 });

    const availabilitySelects = page
      .locator('select[aria-label^="Availability for"]')
      .locator(':scope:not([disabled])')
      .filter({ has: page.locator('option[value="1"]') });

    await expect(availabilitySelects.first()).toBeVisible({ timeout: 5000 });

    const firstSelect = availabilitySelects.first();
    const ariaLabel = await firstSelect.getAttribute('aria-label');
    const targetDate = ariaLabel?.replace('Availability for ', '') ?? '';
    expect(targetDate).toBeTruthy();

    await firstSelect.selectOption('0.5');

    await expect(page.locator('text=Saving availability...')).toBeVisible({ timeout: 5000 });
    await expect(page.locator('text=Saving availability...')).not.toBeVisible({ timeout: 10000 });
    await expect(page.locator('[data-testid="capacity-calendar"] .alert.alert-error')).toHaveCount(0);
    await expectNoRawErrorAlerts(page);

    if (memberId) {
      const period =
        (await page.evaluate(() => localStorage.getItem('headroom_selected_period'))) ?? '2026-02';
      const response = await page.request.get(
        `${API_BASE}/api/capacity?month=${period}&team_member_id=${memberId}`,
        {
          headers: { Authorization: `Bearer ${authToken}` }
        }
      );
      const body = unwrapData<{ details: Array<{ date: string; availability: number }> }>(
        await response.json()
      );
      const changedDetail = body.details.find(
        (detail) => detail.date === targetDate
      );
      expect(changedDetail).toBeDefined();
      expect(changedDetail?.availability).toBe(0.5);
    }
  });

  test('should preselect availability and force blocked days to zero', async ({ page }) => {
    await expect(page.locator('select[aria-label="Select team member"]')).toBeVisible({ timeout: 10000 });

    const teamMemberSelect = page.locator('select[aria-label="Select team member"]');
    if (!memberId) {
      test.fail(true, 'memberId was not created');
      return;
    }

    await createPto(page, authToken, memberId, '2026-02-10');

    await teamMemberSelect.selectOption({ value: memberId });
    await expect(page.locator('[data-testid="capacity-calendar"]')).toBeVisible({ timeout: 10000 });

    const weekdaySelect = page.locator('select[aria-label="Availability for 2026-02-02"]');
    await expect(weekdaySelect).toBeVisible();
    await expect(weekdaySelect).not.toHaveValue('');

    const weekendSelect = page.locator('select[aria-label="Availability for 2026-02-01"]');
    await expect(weekendSelect).toHaveValue('0');
    await expect(weekendSelect).toBeDisabled();

    await page.reload();
    await page.waitForURL('/capacity');
    await teamMemberSelect.selectOption({ value: memberId });

    const ptoSelect = page.locator('select[aria-label="Availability for 2026-02-10"]');
    await expect(ptoSelect).toHaveValue('0');
    await expect(ptoSelect).toBeEnabled();
  });
});
