/**
 * Functional tests: per-path redirect rules.
 *
 * Creates a proxy host with structured redirect rules and verifies that
 * Caddy issues the correct redirect responses for matched paths while
 * still proxying unmatched paths to the upstream.
 *
 * The redirects_json hidden field is injected directly (same pattern used
 * for other non-labeled form controls like ssl_forced_present) so the test
 * doesn't have to click through the MUI Select for each status code.
 *
 * Domain: func-redirects.test
 */
import { test, expect } from '@playwright/test';
import { httpGet, injectFormFields, waitForRoute } from '../../helpers/http';

const DOMAIN = 'func-redirects.test';

test.describe.serial('Per-path Redirect Rules', () => {
  test('setup: create proxy host with redirect rules', async ({ page }) => {
    await page.goto('/proxy-hosts');
    await page.getByRole('button', { name: /create host/i }).click();
    await expect(page.getByRole('dialog')).toBeVisible();

    await page.getByLabel('Name').fill('Functional Redirects Test');
    await page.getByLabel(/domains/i).fill(DOMAIN);
    await page.getByPlaceholder('10.0.0.5:8080').first().fill('echo-server:8080');

    // Inject redirect rules and form flags directly.
    // redirects_json is a hidden input rendered by RedirectsFields whose value
    // reflects React state; setting .value just before submit works because no
    // React render cycle fires between the injection and form data collection.
    await injectFormFields(page, {
      ssl_forced_present: 'on',
      redirects_json: JSON.stringify([
        { from: '/.well-known/carddav', to: '/remote.php/dav/', status: 301 },
        { from: '/.well-known/caldav',  to: '/remote.php/dav/', status: 302 },
      ]),
    });

    await page.getByRole('button', { name: /^create$/i }).click();
    await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 15_000 });
    await expect(page.getByRole('table').getByText('Functional Redirects Test')).toBeVisible({ timeout: 10_000 });

    await waitForRoute(DOMAIN);
  });

  test('matched path receives the configured 301 redirect', async () => {
    const res = await httpGet(DOMAIN, '/.well-known/carddav');
    expect(res.status).toBe(301);
  });

  test('301 redirect Location header points to the configured destination', async () => {
    const res = await httpGet(DOMAIN, '/.well-known/carddav');
    const location = res.headers['location'];
    const locationStr = Array.isArray(location) ? location[0] : (location ?? '');
    expect(locationStr).toBe('/remote.php/dav/');
  });

  test('second matched path receives the configured 302 redirect', async () => {
    const res = await httpGet(DOMAIN, '/.well-known/caldav');
    expect(res.status).toBe(302);
  });

  test('302 redirect Location header points to the configured destination', async () => {
    const res = await httpGet(DOMAIN, '/.well-known/caldav');
    const location = res.headers['location'];
    const locationStr = Array.isArray(location) ? location[0] : (location ?? '');
    expect(locationStr).toBe('/remote.php/dav/');
  });

  test('unmatched path is proxied normally to the upstream', async () => {
    const res = await httpGet(DOMAIN, '/some/other/path');
    expect(res.status).toBe(200);
    expect(res.body).toContain('echo-ok');
  });
});
