package oving5.twitter;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class TwitterAccountTest {

	private TwitterAccount nils;
	private TwitterAccount ole;

	private static void checkFollow(TwitterAccount accountA, TwitterAccount accountB,
			boolean AfollowsB, boolean BfollowsA) {
		if (AfollowsB) {
			assertTrue(accountA.isFollowing(accountB), String.format("%s should be following %s",
					accountA.getUserName(), accountB.getUserName()));
			assertTrue(accountB.isFollowedBy(accountA), String.format("%s should be followed by %s",
					accountB.getUserName(), accountA.getUserName()));
		} else {
			assertFalse(accountA.isFollowing(accountB),
					String.format("%s should not be following %s", accountA.getUserName(),
							accountB.getUserName()));
			assertFalse(accountB.isFollowedBy(accountA),
					String.format("%s should not be followed by %s", accountB.getUserName(),
							accountA.getUserName()));
		}

		if (BfollowsA) {
			assertTrue(accountB.isFollowing(accountA), String.format("%s should be following %s",
					accountB.getUserName(), accountA.getUserName()));
			assertTrue(accountA.isFollowedBy(accountB), String.format("%s should be followed by %s",
					accountA.getUserName(), accountB.getUserName()));
		} else {
			assertFalse(accountB.isFollowing(accountA),
					String.format("%s should not be following %s", accountB.getUserName(),
							accountA.getUserName()));
			assertFalse(accountA.isFollowedBy(accountB),
					String.format("%s should not be followed by %s", accountA.getUserName(),
							accountB.getUserName()));
		}
	}

	@BeforeEach
	public void setUp() {
		nils = new TwitterAccount("Nils");
		ole = new TwitterAccount("Ole");
	}

	@Test
	@DisplayName("Check that the constructor sets up the account correctly")
	public void testConstructor() {
		assertEquals("Nils", nils.getUserName());
		assertEquals(0, nils.getTweetCount());
		assertEquals("Ole", ole.getUserName());
		assertEquals(0, ole.getTweetCount());
	}

	@Test
	@DisplayName("Follow")
	public void testFollow() {
		nils.follow(ole);
		TwitterAccountTest.checkFollow(nils, ole, true, false);

		ole.follow(nils);
		TwitterAccountTest.checkFollow(nils, ole, true, true);
	}

	@Test
	@DisplayName("Unfollow")
	public void testUnfollow() {
		TwitterAccountTest.checkFollow(nils, ole, false, false);

		nils.follow(ole);
		TwitterAccountTest.checkFollow(nils, ole, true, false);

		nils.unfollow(ole);
		TwitterAccountTest.checkFollow(nils, ole, false, false);
	}

	@Test
	@DisplayName("Tests that a new tweet is correct")
	public void testNewTweet() {
		nils.tweet("Kvitre!");
		assertEquals(1, nils.getTweetCount(), "Nils' tweet count should be 1");
		assertEquals("Kvitre!", nils.getTweet(1).getText(), "The text should be 'Tweet'");

		nils.tweet("Kvitre igjen!");
		assertEquals(2, nils.getTweetCount());
		assertEquals("Kvitre igjen!", nils.getTweet(1).getText());
		assertEquals("Kvitre!", nils.getTweet(2).getText());
	}

	@Test
	@DisplayName("Tests exceptions for illegal tweets")
	public void testIllegalTweet() {
		assertThrows(RuntimeException.class, () -> {
			nils.getTweet(1);
		}, "Should not be able to retrieve a tweet that does not exist");

		assertThrows(RuntimeException.class, () -> {
			nils.getTweet(-1);
		}, "Should not be able to retrieve a tweet that does not exist");

		nils.tweet("Tweet!");

		assertThrows(RuntimeException.class, () -> {
			nils.getTweet(2);
		}, "Should not be able to retrieve a tweet that does not exist");

		assertThrows(RuntimeException.class, () -> {
			nils.getTweet(-1);
		}, "Should not be able to retrieve a tweet that does not exist");
	}

	@Test
	@DisplayName("Check that retweet works, including retweeting a retweet")
	public void testRetweet() {
		TwitterAccount kari = new TwitterAccount("Kari");

		nils.tweet("Kvitre!");
		assertEquals(1, nils.getTweetCount());
		assertEquals("Kvitre!", nils.getTweet(1).getText());

		ole.retweet(nils.getTweet(1));
		assertEquals(1, nils.getTweetCount());
		assertEquals(1, nils.getRetweetCount());
		assertEquals(1, ole.getTweetCount());
		assertEquals(0, ole.getRetweetCount());
		assertEquals("Kvitre!", ole.getTweet(1).getText());
		assertEquals(nils.getTweet(1), ole.getTweet(1).getOriginalTweet());

		kari.retweet(ole.getTweet(1));
		assertEquals(1, nils.getTweetCount());
		assertEquals(2, nils.getRetweetCount());
		assertEquals(1, ole.getTweetCount());
		assertEquals(0, ole.getRetweetCount());
		assertEquals(1, kari.getTweetCount());
		assertEquals(0, kari.getRetweetCount());
		assertEquals("Kvitre!", kari.getTweet(1).getText());
		assertEquals(nils.getTweet(1), kari.getTweet(1).getOriginalTweet());
	}
}
