# tests.py

import subprocess
import json
import os
from django.test import TestCase
from django.conf import settings
from PIL import Image
from django.core.files.uploadedfile import SimpleUploadedFile
import random
import string

class AccountsAPITests(TestCase):

    def run_httpie_command(self, command):
        result = subprocess.run(command, shell=True, capture_output=True, text=True)
        return result.stdout, result.stderr, result.returncode

    def setUp(self):
        # Get http_domain from settings
        self.http_domain = settings.TEST_HTTP_DOMAIN or 'http://127.0.0.1:8000'
        # Login and get the token
        email = settings.TEST_USER_EMAIL or 'default_email@test.com'
        password = settings.TEST_USER_PASSWORD or 'default_password'
        
        login_command = f"http POST {self.http_domain}/auth/register/login/ email='{email}' password='{password}'"
        login_stdout, login_stderr, login_returncode = self.run_httpie_command(login_command)
        self.assertEqual(login_returncode, 0, f"Login failed: {login_stderr}")
        login_response = json.loads(login_stdout)
        #print(f"Login response: {login_response}")
        self.token = login_response['access_token']
        #print(f"Token: {self.token}")
        self.refresh_token = login_response['refresh_token']
        #print(f"Refresh Token: {self.refresh_token}")
        
        # Ensure a nivel is created before running any tests
        self.test_niveis_create()

    def tearDown(self):
        # Logout and blacklist the token
        logout_command = f"http POST {self.http_domain}/auth/register/logout/ token='{self.token}'"
        logout_stdout, logout_stderr, logout_returncode = self.run_httpie_command(logout_command)
        self.assertEqual(logout_returncode, 0, f"Logout failed: {logout_stderr}")
        self.assertIn("Token blacklisted successfully", logout_stdout)

    def create_test_image(self, file_path, size=(100, 100)):
        # Create a simple image for testing
        image = Image.new('RGB', size, color = (73, 109, 137))
        image.save(file_path)
        return file_path

    # def test_usuario_create_without_foto(self):
    #     ### create a random lower case email @test.com
    #     random_email = ''.join(random.choices(string.ascii_lowercase, k=10)) + '@test.com'
    #     random_password = ''.join(random.choices(string.ascii_lowercase + string.ascii_uppercase + string.digits, k=10))
        
        
    #     create_command = f"http -A bearer -a {self.token} -f POST {self.http_domain}/accounts/usuarios/ email='{random_email}' password='{random_password}' categoria='admin'"
    #     create_stdout, create_stderr, create_returncode = self.run_httpie_command(create_command)
    #     self.assertEqual(create_returncode, 0, f"Create failed: {create_stderr}")
    #     create_response = json.loads(create_stdout)
    #     self.assertIn('id', create_response, "Create response does not contain ID")
    #     # Store user ID for subsequent tests
    #     self.new_user_id = create_response['id']
    
    
    def test_niveis_create(self):
        permissions = '{"app_label":"panel","codename":"add_universidade","name":"Can add Universidade"},{"app_label":"panel","codename":"change_universidade","name":"Can change Universidade"},{"app_label":"panel","codename":"delete_universidade","name":"Can delete Universidade"},{"app_label":"panel","codename":"view_universidade","name":"Can view Universidade"}'
        create_command = f"http -A bearer -a {self.token} POST {self.http_domain}/accounts/niveis/ name='Acesso Total Universidade' permissions:=['{permissions}']"
        create_stdout, create_stderr, create_returncode = self.run_httpie_command(create_command)
        self.assertEqual(create_returncode, 0, f"Níveis create failed: {create_stderr}")
        create_response = json.loads(create_stdout)
        #print(f"Nvel Create Response: {create_response}")
        self.assertIn('id', create_response['results'], "Níveis create response does not contain ID")
        # Store nivel ID for subsequent tests
        self.new_nivel_id = create_response['results']['id']

    def test_usuario_create(self):
        ### Generate random data to create a user
        random_email = ''.join(random.choices(string.ascii_lowercase, k=10)) + '@test.com'
        random_password = ''.join(random.choices(string.ascii_lowercase + string.ascii_uppercase + string.digits, k=10))
        random_telefone = ''.join(random.choices(string.digits, k=10))
        random_first_name = ''.join(random.choices(string.ascii_lowercase + string.ascii_uppercase, k=10))
        random_last_name = ''.join(random.choices(string.ascii_lowercase + string.ascii_uppercase, k=10))
        test_image_path = self.create_test_image('test_image.jpg')
        
        nivel_id = self.new_nivel_id
        
        create_command = f"http -A bearer -a {self.token} -f POST {self.http_domain}/accounts/usuarios/ email='{random_email}' password='{random_password}' categoria='admin' first_name='{random_first_name}' last_name='{random_last_name}' telefone='{random_telefone}' foto@'{test_image_path}' nivel='{nivel_id}'"
        create_stdout, create_stderr, create_returncode = self.run_httpie_command(create_command)
        os.remove(test_image_path)  # Clean up the test image file
        self.assertEqual(create_returncode, 0, f"Create failed: {create_stderr}")
        create_response = json.loads(create_stdout)
        #print(f"Create response: {create_response}")
        self.assertIn('id', create_response['results'], "Create response does not contain ID")
        # Store user ID for subsequent tests
        self.new_user_id = create_response['results']['id']

    def test_usuarios_list(self):
        list_command = f"http -A bearer -a {self.token} -f GET {self.http_domain}/accounts/usuarios/"
        list_stdout, list_stderr, list_returncode = self.run_httpie_command(list_command)
        self.assertEqual(list_returncode, 0, f"List failed: {list_stderr}")
        list_response = json.loads(list_stdout)
        self.assertIsInstance(list_response['results'], list, "List response is not a list")

    def test_usuario_retrieve(self):
        if not hasattr(self, 'new_user_id'):
            self.test_usuario_create()  # Create a new user if not already created

        user_id = self.new_user_id  # Use the created user's ID
        retrieve_command = f"http -A bearer -a {self.token} -f GET {self.http_domain}/accounts/usuarios/{user_id}/"
        retrieve_stdout, retrieve_stderr, retrieve_returncode = self.run_httpie_command(retrieve_command)
        self.assertEqual(retrieve_returncode, 0, f"Retrieve failed: {retrieve_stderr}")
        retrieve_response = json.loads(retrieve_stdout)
        self.assertIn('email', retrieve_response, "Retrieve response does not contain email")

    def test_usuario_update(self):
        if not hasattr(self, 'new_user_id'):
            self.test_usuario_create()  # Create a new user with photo if not already created
        
        ### Generate random data to create a user
        random_email = ''.join(random.choices(string.ascii_lowercase, k=10)) + '@test.com'
        random_password = ''.join(random.choices(string.ascii_lowercase + string.ascii_uppercase + string.digits, k=10))
        random_telefone = ''.join(random.choices(string.digits, k=10))
        random_first_name = ''.join(random.choices(string.ascii_lowercase + string.ascii_uppercase, k=10))
        random_last_name = ''.join(random.choices(string.ascii_lowercase + string.ascii_uppercase, k=10))
        test_image_path = self.create_test_image('test_image.jpg')
        
        nivel_id = self.new_nivel_id

        user_id = self.new_user_id  # Use the created user's ID
        test_image_path = self.create_test_image('whatever.jpg')
        update_command = f"http -A bearer -a {self.token} -f PUT {self.http_domain}/accounts/usuarios/{user_id}/ email='{random_email}' password='{random_password}' categoria='admin' first_name='{random_first_name}' last_name='{random_last_name}' telefone='{random_telefone}' foto@'{test_image_path}' nivel='{nivel_id}'"
        update_stdout, update_stderr, update_returncode = self.run_httpie_command(update_command)
        os.remove(test_image_path)  # Clean up the test image file
        self.assertEqual(update_returncode, 0, f"Update failed: {update_stderr}")
        update_response = json.loads(update_stdout)
        self.assertIn('email', update_response['results'], "Update response does not contain email")

    def test_usuario_delete(self):
        if not hasattr(self, 'new_user_id'):
            self.test_usuario_create()  # Create a new user with photo if not already created

        user_id = self.new_user_id  # Use the created user's ID
        delete_command = f"http -A bearer -a {self.token} DELETE {self.http_domain}/accounts/usuarios/{user_id}/"
        delete_stdout, delete_stderr, delete_returncode = self.run_httpie_command(delete_command)
        self.assertEqual(delete_returncode, 0, f"Delete failed: {delete_stderr}")
        self.assertEqual(delete_stdout.strip(), '', "Delete response should be empty for 204 No Content")

    def test_permissions_list(self):
        list_command = f"http -A bearer -a {self.token} GET {self.http_domain}/accounts/permissions/"
        list_stdout, list_stderr, list_returncode = self.run_httpie_command(list_command)
        self.assertEqual(list_returncode, 0, f"Permissions list failed: {list_stderr}")
        list_response = json.loads(list_stdout)
        self.assertIsInstance(list_response, list, "Permissions list response is not a list")

    def test_niveis_list(self):
        list_command = f"http -A bearer -a {self.token} GET {self.http_domain}/accounts/niveis/"
        list_stdout, list_stderr, list_returncode = self.run_httpie_command(list_command)
        self.assertEqual(list_returncode, 0, f"Níveis list failed: {list_stderr}")
        list_response = json.loads(list_stdout)
        self.assertIsInstance(list_response['results'], list, "Níveis list response is not a list")

    def test_niveis_retrieve(self):
        if not hasattr(self, 'new_nivel_id'):
            self.test_niveis_create()  # Create a new nivel if not already created

        nivel_id = self.new_nivel_id  # Use the created nivel's ID
        retrieve_command = f"http -A bearer -a {self.token} GET {self.http_domain}/accounts/niveis/{nivel_id}/"
        retrieve_stdout, retrieve_stderr, retrieve_returncode = self.run_httpie_command(retrieve_command)
        self.assertEqual(retrieve_returncode, 0, f"Níveis retrieve failed: {retrieve_stderr}")
        retrieve_response = json.loads(retrieve_stdout)
        #print(f"Retrieve response: {retrieve_response}")
        self.assertIn('name', retrieve_response, "Níveis retrieve response does not contain name")

    def test_niveis_update(self):
        if not hasattr(self, 'new_nivel_id'):
            self.test_niveis_create()  # Create a new nivel if not already created

        nivel_id = self.new_nivel_id  # Use the created nivel's ID
        permissions = '{"app_label":"panel","codename":"add_universidade","name":"Can add Universidade"},{"app_label":"panel","codename":"change_universidade","name":"Can change Universidade"},{"app_label":"panel","codename":"delete_universidade","name":"Can delete Universidade"},{"app_label":"panel","codename":"view_universidade","name":"Can view Universidade"},{"app_label":"panel","codename":"view_remaxnomundo","name":"Can view RE/MAX no Mundo"},{"app_label":"accounts","codename":"view_usuario","name":"Can view Usuario"}'
        update_command = f"http -A bearer -a {self.token} PUT {self.http_domain}/accounts/niveis/{nivel_id}/ name='Acesso Total Universidade 2' permissions:=['{permissions}']"
        update_stdout, update_stderr, update_returncode = self.run_httpie_command(update_command)
        self.assertEqual(update_returncode, 0, f"Níveis update failed: {update_stderr}")
        update_response = json.loads(update_stdout)
        self.assertIn('name', update_response['results'], "Níveis update response does not contain name")

    def test_niveis_delete(self):
        if not hasattr(self, 'new_nivel_id'):
            self.test_niveis_create()  # Create a new nivel if not already created

        nivel_id = self.new_nivel_id  # Use the created nivel's ID
        delete_command = f"http -A bearer -a {self.token} DELETE {self.http_domain}/accounts/niveis/{nivel_id}/"
        delete_stdout, delete_stderr, delete_returncode = self.run_httpie_command(delete_command)
        self.assertEqual(delete_returncode, 0, f"Níveis delete failed: {delete_stderr}")
        self.assertEqual(delete_stdout.strip(), '', "Delete response should be empty for 204 No Content")
