package org.thoughtcrime.securesms.database

import android.app.Application
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.signal.core.models.ServiceId.ACI
import org.thoughtcrime.securesms.database.model.DistributionListId
import org.thoughtcrime.securesms.database.model.DistributionListRecord
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.testutil.RecipientTestRule
import java.util.UUID

@RunWith(RobolectricTestRunner::class)
@Config(manifest = Config.NONE, application = Application::class)
class DistributionListTablesTest {

  @get:Rule
  val recipients = RecipientTestRule()

  private lateinit var distributionDatabase: DistributionListTables

  @Before
  fun setup() {
    distributionDatabase = SignalDatabase.distributionLists
  }

  @Test
  fun createList_whenNoConflict_insertSuccessfully() {
    val id: DistributionListId? = distributionDatabase.createList("test", recipientList(1, 2, 3))
    Assert.assertNotNull(id)
  }

  @Test
  fun getList_returnCorrectList() {
    val members: List<RecipientId> = createRecipients(3)

    val id: DistributionListId? = distributionDatabase.createList("test", members)
    Assert.assertNotNull(id)

    val record: DistributionListRecord? = distributionDatabase.getList(id!!)
    Assert.assertNotNull(record)
    Assert.assertEquals(id, record!!.id)
    Assert.assertEquals("test", record.name)
    Assert.assertEquals(members, record.members)
  }

  @Test
  fun getMembers_returnsCorrectMembers() {
    val members: List<RecipientId> = createRecipients(3)

    val id: DistributionListId? = distributionDatabase.createList("test", members)
    Assert.assertNotNull(id)

    val foundMembers: List<RecipientId> = distributionDatabase.getMembers(id!!)
    Assert.assertEquals(members, foundMembers)
  }

  @Test
  fun givenStoryExists_getStoryType_returnsStoryWithReplies() {
    val id: DistributionListId? = distributionDatabase.createList("test", recipientList(1, 2, 3))
    Assert.assertNotNull(id)

    val storyType = distributionDatabase.getStoryType(id!!)
    Assert.assertEquals(StoryType.STORY_WITH_REPLIES, storyType)
  }

  @Test
  fun givenStoryExistsAndMarkedNoReplies_getStoryType_returnsStoryWithoutReplies() {
    val id: DistributionListId? = distributionDatabase.createList("test", recipientList(1, 2, 3))
    Assert.assertNotNull(id)
    distributionDatabase.setAllowsReplies(id!!, false)

    val storyType = distributionDatabase.getStoryType(id)
    Assert.assertEquals(StoryType.STORY_WITHOUT_REPLIES, storyType)
  }

  @Test(expected = IllegalStateException::class)
  fun givenStoryDoesNotExist_getStoryType_throwsIllegalStateException() {
    distributionDatabase.getStoryType(DistributionListId.from(12))
    Assert.fail("Expected an assertion error.")
  }

  private fun createRecipients(count: Int): List<RecipientId> {
    return (0 until count).map {
      SignalDatabase.recipients.getOrInsertFromServiceId(ACI.from(UUID.randomUUID()))
    }
  }

  private fun recipientList(vararg ids: Long): List<RecipientId> {
    return ids.map { RecipientId.from(it) }
  }
}
