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

const adminAuth = {
  authenticated: true,
  csrfToken: 'test-csrf',
  user: {
    id: 1,
    email: 'admin@learnitive.test',
    displayName: 'Template Admin',
    avatarUrl: null,
    role: 'admin',
    status: 'active',
  },
  entitlement: {
    tier: 'pro',
    pro: true,
    blocked: false,
    quota: 1000,
    usage: 0,
    remaining: 1000,
  },
} as const;

function json(route: Route, status: number, body: unknown) {
  return route.fulfill({
    status,
    contentType: 'application/json',
    body: JSON.stringify(body),
  });
}

async function mockAdminTemplateApi(
  page: Page,
  options: { uploadError?: { status: number; code: string } } = {},
) {
  const templates: Array<Record<string, unknown>> = [];
  let uploadUrl = '';

  await page.route('**/api/**', async (route) => {
    const request = route.request();
    const url = new URL(request.url());
    const method = request.method();

    if (url.pathname === '/api/config/public') {
      return json(route, 200, {
        saasEnabled: true,
        googleAuthEnabled: false,
        contactEnabled: false,
        shopUrl: '',
      });
    }
    if (url.pathname === '/api/auth/me') return json(route, 200, adminAuth);
    if (url.pathname === '/api/user/settings' && method === 'GET') {
      return json(route, 200, { settings: {} });
    }
    if (url.pathname === '/api/admin/templates' && method === 'GET') {
      return json(route, 200, { items: templates, institutions: [], categories: [] });
    }
    if (url.pathname === '/api/admin/templates/upload' && method === 'POST') {
      uploadUrl = request.url();
      if (options.uploadError) {
        return json(route, options.uploadError.status, { error: options.uploadError.code });
      }
      const slug = url.searchParams.get('slug') || 'uploaded-template';
      const item = {
        id: slug,
        slug,
        name: url.searchParams.get('name') || 'Uploaded Template',
        tier: url.searchParams.get('tier') === 'pro' ? 'pro' : 'free',
        status: 'draft',
        category: '',
        provenance: 'learnitive',
        entryFile: 'main.tex',
        version: '1.0.0',
        updatedAt: '2026-08-23',
      };
      templates.push(item);
      return json(route, 201, { item });
    }

    return json(route, 404, { error: 'not_mocked' });
  });

  return { getUploadUrl: () => uploadUrl };
}

test('Admin can create a draft template from a ZIP and continue in the metadata editor', async ({
  page,
}) => {
  const api = await mockAdminTemplateApi(page);
  await page.goto('/admin/templates');

  await expect(page.getByRole('heading', { name: 'Templates' })).toBeVisible();
  await page.getByRole('button', { name: 'Create template' }).click();

  const dialog = page.getByRole('dialog', { name: 'Create template' });
  await expect(dialog).toBeVisible();
  await dialog.getByLabel('Template name').fill('Advanced Research Thesis');
  await expect(dialog.getByLabel('Slug')).toHaveValue('advanced-research-thesis');
  await dialog.getByLabel('Access').selectOption('pro');
  await dialog.locator('input[type="file"]').setInputFiles({
    name: 'advanced-research-thesis.zip',
    mimeType: 'application/zip',
    buffer: Buffer.from('PK\u0003\u0004test-template'),
  });

  await dialog.getByRole('button', { name: 'Create template' }).click();
  await expect(dialog).toBeHidden();

  const uploadUrl = new URL(api.getUploadUrl());
  expect(uploadUrl.searchParams.get('name')).toBe('Advanced Research Thesis');
  expect(uploadUrl.searchParams.get('slug')).toBe('advanced-research-thesis');
  expect(uploadUrl.searchParams.get('tier')).toBe('pro');

  await expect(page.getByText('Template editor')).toBeVisible();
  await expect(page.getByRole('heading', { name: 'Advanced Research Thesis' })).toBeVisible();
  const editor = page.locator('.interactive-admin-template-editor');
  const status = editor.locator('label').filter({ hasText: /^Status$/u }).locator('..').locator('select');
  await expect(status).toHaveValue('draft');
});

test('Create template keeps the dialog values when the server rejects a duplicate slug', async ({
  page,
}) => {
  await mockAdminTemplateApi(page, {
    uploadError: { status: 409, code: 'template_already_exists' },
  });
  await page.goto('/admin/templates');
  await page.getByRole('button', { name: 'Create template' }).click();

  const dialog = page.getByRole('dialog', { name: 'Create template' });
  await dialog.getByLabel('Template name').fill('Existing Thesis');
  await dialog.locator('input[type="file"]').setInputFiles({
    name: 'existing-thesis.zip',
    mimeType: 'application/zip',
    buffer: Buffer.from('PK\u0003\u0004duplicate-template'),
  });
  await dialog.getByRole('button', { name: 'Create template' }).click();

  await expect(dialog).toBeVisible();
  await expect(dialog.getByText('A template with this slug already exists. Choose a different slug.')).toBeVisible();
  await expect(dialog.getByLabel('Template name')).toHaveValue('Existing Thesis');
  await expect(dialog.getByLabel('Slug')).toHaveValue('existing-thesis');
  await expect(dialog.getByText('existing-thesis.zip')).toBeVisible();
});
