from django.test import TestCase
from django.urls import reverse
from django.contrib.auth import get_user_model


from rest_framework.test import APIClient
from rest_framework import status

CREATE_USER_URL = reverse('users:create')
TOKEN_URL = reverse('users:token')
ME_URL = reverse('users:me')


def create_user(**params):
    return get_user_model().objects.create_user(**params)


class PublicUsersAPITests(TestCase):
    '''Test users api public'''

    def setUp(self):
        self.client = APIClient()

    def test_create_valid_user_success(self):
        '''Test creting new user with valid credentials
         is created succefully
        '''
        payload = {
            'email': 'test@londonappdev.com',
            'password': 'testpass123',
            'name': 'Test name'
        }
        # create_user(**payload)
        res = self.client.post(CREATE_USER_URL, payload)
        self.assertEqual(res.status_code, status.HTTP_201_CREATED)
        user = get_user_model().objects.get(**res.data)
        self.assertTrue(user.check_password(payload['password']))
        self.assertNotIn('password', res.data)
        self.assertEqual(user.email, payload['email'])

    def test_user_exists(self):
        '''Test creating user that already exists fails'''
        payload = {'email': 'test@londondevappdev', 'password': 'testpass123'}
        create_user(**payload)
        res = self.client.post(CREATE_USER_URL, payload)
        self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)

    def test_password_too_short(self):
        '''Test that password must be more than 5 characters long'''
        payload = {'email': 'test@londonappdev', 'password': 'tew'}
        res = self.client.post(CREATE_USER_URL, payload)

        self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)
        user_exists = get_user_model().objects.filter(
            email=payload['email']
        ).exists()
        self.assertFalse(user_exists)

    def test_create_token_for_user(self):
        '''Test that a token is created for the user '''
        payload = {'email': 'test@londondappdev.com',
                   'password': 'testpassword'}
        create_user(**payload)
        res = self.client.post(TOKEN_URL, payload)

        self.assertIn('token', res.data)
        self.assertEqual(res.status_code, status.HTTP_200_OK)

    def test_create_token_invalid_credentials(self):
        '''Test that token is not created if invalid credentials are given'''
        payload1 = {'email': 'test@londonappdev.com',
                    'password': 'testpass123'}
        create_user(**payload1)
        payload = {'email': 'test@londonappdev.com', 'password': 'testpa'}
        res = self.client.post(TOKEN_URL, payload)
        self.assertNotIn('token', res.data)
        self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_token_no_user(self):
        '''Test that token is not created if user does not exists '''
        payload = {'email': 'test@londonappdev.com', 'password': 'testpass123'}
        res = self.client.post(TOKEN_URL, payload)
        self.assertNotIn('token', res.data)
        self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_token_missing_field(self):
        '''Test that email and password are required'''
        payload = {'email': 'test@londonappdev.com', 'password': ''}
        res = self.client.post(TOKEN_URL, payload)
        self.assertNotIn('token', res.data)
        self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)

    def test_authentication_is_required_on_me(self):
        res = self.client.get(ME_URL)
        self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED)


class PrivateAPITests(TestCase):
    '''Requires authentication to access the endpoints '''

    def setUp(self):
        self.user = create_user(
            email='test@londonappdev.com',
            password='testpass123',
            name='name'
        )
        self.client = APIClient()
        self.client.force_authenticate(user=self.user)

    def test_retrive_profile_success(self):
        '''Test that user can retrieve his profile successfully'''
        res = self.client.get(ME_URL)
        self.assertEqual(
            res.data, {'name': self.user.name, 'email': self.user.email})
        self.assertNotIn('password', res.data)

    def test_post_me_not_allowed(self):
        '''Test that POST is not allowed on the me url'''
        res = self.client.post(ME_URL, {})

        self.assertEqual(res.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)

    def test_user_can_updated_profile_success(self):
        payload = {'name': 'new_name', 'password': 'password123'}

        res = self.client.patch(ME_URL, payload)

        self.user.refresh_from_db()
        self.assertEqual(self.user.name, payload['name'])
        self.assertEqual(res.status_code, status.HTTP_200_OK)

    def test_user_can_update_whole_profile(self):
        '''Test user can updated all profile details once'''
        payload = {'name': 'new_name',
                   'email': 'test@gmail.com', 'password': 'password123'}
        res = self.client.put(ME_URL, payload)
        self.user.refresh_from_db()
        self.assertEqual(self.user.name, payload['name'])
        self.assertEqual(self.user.email, payload['email'])
        self.assertEqual(res.status_code, status.HTTP_200_OK)
