import { afterEach, beforeEach, expect, test, vi } from 'vitest';

import { db } from '../../index.js';

beforeEach(() => {
  vi.useFakeTimers();
  vi.setSystemTime(new Date('2017-11-20T11:23:45Z'));
});

afterEach(() => {
  vi.restoreAllMocks();
});

test('creates a new API token', async function () {
  let user = await db.user.create({});
  await db.mswSession.create({ user });

  let body = JSON.stringify({ api_token: { name: 'foooo' } });
  let response = await fetch('/api/v1/me/tokens', { method: 'PUT', body });
  expect(response.status).toBe(200);

  let token = db.apiToken.findMany()[0];
  expect(token).toBeTruthy();

  expect(await response.json()).toMatchInlineSnapshot(`
    {
      "api_token": {
        "crate_scopes": null,
        "created_at": "2017-11-20T11:23:45.000Z",
        "endpoint_scopes": null,
        "expired_at": null,
        "id": 1,
        "last_used_at": null,
        "name": "foooo",
        "token": "6270739405881613",
      },
    }
  `);
});

test('creates a new API token with scopes', async function () {
  let user = await db.user.create({});
  await db.mswSession.create({ user });

  let body = JSON.stringify({
    api_token: {
      name: 'foooo',
      crate_scopes: ['serde', 'serde-*'],
      endpoint_scopes: ['publish-update'],
    },
  });
  let response = await fetch('/api/v1/me/tokens', { method: 'PUT', body });
  expect(response.status).toBe(200);

  let token = db.apiToken.findMany()[0];
  expect(token).toBeTruthy();

  expect(await response.json()).toMatchInlineSnapshot(`
    {
      "api_token": {
        "crate_scopes": [
          "serde",
          "serde-*",
        ],
        "created_at": "2017-11-20T11:23:45.000Z",
        "endpoint_scopes": [
          "publish-update",
        ],
        "expired_at": null,
        "id": 1,
        "last_used_at": null,
        "name": "foooo",
        "token": "6270739405881613",
      },
    }
  `);
});

test('creates a new API token with expiry date', async function () {
  let user = await db.user.create({});
  await db.mswSession.create({ user });

  let body = JSON.stringify({
    api_token: {
      name: 'foooo',
      expired_at: '2023-12-24T12:34:56Z',
    },
  });
  let response = await fetch('/api/v1/me/tokens', { method: 'PUT', body });
  expect(response.status).toBe(200);

  let token = db.apiToken.findMany()[0];
  expect(token).toBeTruthy();

  expect(await response.json()).toMatchInlineSnapshot(`
    {
      "api_token": {
        "crate_scopes": null,
        "created_at": "2017-11-20T11:23:45.000Z",
        "endpoint_scopes": null,
        "expired_at": "2023-12-24T12:34:56.000Z",
        "id": 1,
        "last_used_at": null,
        "name": "foooo",
        "token": "6270739405881613",
      },
    }
  `);
});

test('returns an error for an invalid endpoint scope', async function () {
  let user = await db.user.create({});
  await db.mswSession.create({ user });

  let body = JSON.stringify({ api_token: { name: 'foooo', endpoint_scopes: ['invalid'] } });
  let response = await fetch('/api/v1/me/tokens', { method: 'PUT', body });
  expect(response.status).toBe(400);
  expect(await response.json()).toMatchInlineSnapshot(`
    {
      "errors": [
        {
          "detail": "invalid endpoint scope",
        },
      ],
    }
  `);
});

test('returns an error if unauthenticated', async function () {
  let body = JSON.stringify({ api_token: {} });
  let response = await fetch('/api/v1/me/tokens', { method: 'PUT', body });
  expect(response.status).toBe(403);
  expect(await response.json()).toMatchInlineSnapshot(`
    {
      "errors": [
        {
          "detail": "must be logged in to perform that action",
        },
      ],
    }
  `);
});
