import { test } from '@japa/runner'
import { DataNamespace, DataFile, IDataFile, ThingKind, DataFileKind } from '../../../src/index.js'

const organization = 'test-organization'

test.group('DataFile.fromDataNamespace()', () => {
  test('sets the kind', ({ assert }) => {
    const p1 = DataNamespace.fromName('p1')
    const result = DataFile.fromDataNamespace(p1, organization)
    assert.equal(result.kind, DataFileKind)
  })

  test('sets the organization', ({ assert }) => {
    const p1 = DataNamespace.fromName('p1')
    const result = DataFile.fromDataNamespace(p1, organization)
    assert.equal(result.organization, organization)
  })

  test('sets the name', ({ assert }) => {
    const p1 = DataNamespace.fromName('p1')
    const result = DataFile.fromDataNamespace(p1, organization)
    assert.equal(result.info.name, 'p1')
  })

  test('sets the key', ({ assert }) => {
    const p1 = DataNamespace.fromName('p1')
    const result = DataFile.fromDataNamespace(p1, organization)
    assert.equal(result.key, p1.key)
  })

  test('sets the configured owner', ({ assert }) => {
    const p1 = DataNamespace.fromName('p1')
    const result = DataFile.fromDataNamespace(p1, organization, 'other')
    assert.equal(result.owner, 'other')
  })

  test('respects schema instead of instance', ({ assert }) => {
    const p1 = DataNamespace.fromName('p1')
    const result = DataFile.fromDataNamespace(p1.toJSON(), organization)
    assert.equal(result.info.name, 'p1')
  })
})

test.group('constructor()', () => {
  test('creates a default data file', ({ assert }) => {
    const result = new DataFile()
    assert.equal(result.kind, DataFileKind)
    assert.isUndefined(result.owner)
    assert.typeOf(result.key, 'string')
    assert.typeOf(result.lastModified, 'object')
  })

  test('creates a data file from the schema values', ({ assert }) => {
    const schema: IDataFile = {
      kind: DataFileKind,
      organization,
      info: {
        kind: ThingKind,
        name: 'hello',
        description: 'a desc',
      },
      owner: 'me',
      key: '123',
      parents: ['p1'],
      permissionIds: ['pr1'],
      permissions: [
        {
          addingUser: '123',
          key: '123',
          kind: 'Core#Permission',
          granteeId: '345',
          role: 'commenter',
          type: 'organization',
          itemId: '678',
        },
      ],
      lastModified: { byMe: false, time: 0, user: 'id', name: 'test' },
      labels: ['l1'],
    }
    const result = new DataFile(schema)
    assert.equal(result.kind, DataFileKind)
    assert.equal(result.organization, organization)
    assert.equal(result.info.name, 'hello')
    assert.equal(result.owner, 'me')
    assert.equal(result.key, '123')
    assert.deepEqual(result.parents, ['p1'])
    assert.deepEqual(result.permissionIds, ['pr1'])
    assert.typeOf(result.permissions, 'array')
    assert.deepEqual(result.lastModified, schema.lastModified)
    assert.deepEqual(result.labels, ['l1'])
  })

  test('creates a data file from the JSON schema string', ({ assert }) => {
    const schema: IDataFile = {
      kind: DataFileKind,
      organization,
      info: {
        kind: ThingKind,
        name: 'hello',
        description: 'a desc',
      },
      owner: 'me',
      key: '123',
      parents: ['p1'],
      permissionIds: ['pr1'],
      permissions: [
        {
          addingUser: '123',
          key: '123',
          kind: 'Core#Permission',
          granteeId: '345',
          role: 'commenter',
          type: 'organization',
          itemId: '678',
        },
      ],
      lastModified: { byMe: false, time: 0, user: 'id', name: 'test' },
    }
    const result = new DataFile(JSON.stringify(schema))
    assert.equal(result.kind, DataFileKind)
    assert.equal(result.organization, organization)
    assert.equal(result.info.name, 'hello')
    assert.equal(result.owner, 'me')
    assert.equal(result.key, '123')
    assert.deepEqual(result.lastModified, schema.lastModified)
  })

  test('throws when invalid schema', ({ assert }) => {
    assert.throws(() => {
      new DataFile(
        JSON.stringify({
          name: 'a name',
        })
      )
    })
  })
})

test.group('toJSON()', () => {
  test('serializes the kind', ({ assert }) => {
    const file = new DataFile()
    const result = file.toJSON()
    assert.equal(result.kind, DataFileKind)
  })

  test('serializes the key', ({ assert }) => {
    const file = new DataFile()
    const result = file.toJSON()
    assert.equal(result.key, file.key)
  })

  // the "key" test tests whether the parent toJSON() is called.
})

test.group('DataFile.fromName()', () => {
  test('sets the kind', ({ assert }) => {
    const result = DataFile.fromName('name', organization)
    assert.equal(result.kind, DataFileKind)
  })

  test('sets the organization', ({ assert }) => {
    const result = DataFile.fromName('name', organization)
    assert.equal(result.organization, organization)
  })

  test('sets the name', ({ assert }) => {
    const result = DataFile.fromName('name', organization)
    assert.equal(result.info.name, 'name')
  })

  test('sets the key', ({ assert }) => {
    const result = DataFile.fromName('name', organization)
    assert.typeOf(result.key, 'string')
    assert.notEqual(result.key, '')
  })

  test('sets the owner', ({ assert }) => {
    const result = DataFile.fromName('name', organization, 'other')
    assert.equal(result.owner, 'other')
  })
})

test.group('DataFile.fromName()', () => {
  test('sets the kind', ({ assert }) => {
    const result = DataFile.fromName('name', organization)
    assert.equal(result.kind, DataFileKind)
  })

  test('sets the organization', ({ assert }) => {
    const result = DataFile.fromName('name', organization)
    assert.equal(result.organization, organization)
  })

  test('sets the name', ({ assert }) => {
    const result = DataFile.fromName('name', organization)
    assert.equal(result.info.name, 'name')
  })

  test('sets the key', ({ assert }) => {
    const result = DataFile.fromName('name', organization)
    assert.typeOf(result.key, 'string')
    assert.notEqual(result.key, '')
  })

  test('sets the owner', ({ assert }) => {
    const result = DataFile.fromName('name', organization, 'other')
    assert.equal(result.owner, 'other')
  })
})
