from core.tests.base_test import SkillboxTestCase
from portfolio.factories import ProjectFactory
from portfolio.models import Project
from users.factories import SchoolClassFactory
from users.models import User

project_query = """
query ProjectQuery($id: ID!) {
  project(id: $id) {
    id
  }
}        
"""


class ProjectQueryTestCaswe(SkillboxTestCase):
    def _test_direct_project_access(self, user: User, should_have_access: bool):
        result = self.get_client(user).get_result(project_query, variables={
            'id': self.project1.graphql_id
        })
        self.assertIsNone(result.errors)
        if should_have_access:
            self.assertEqual(result.data.get('project').get('id'), self.project1.graphql_id)
        else:
            self.assertIsNone(result.data.get('project'))

    def setUp(self):
        self.createDefault()
        school_class1 = SchoolClassFactory(users=[self.teacher, self.student1])
        school_class2 = SchoolClassFactory(users=[self.teacher2, self.student2])

        self.project1 = ProjectFactory(student=self.student1)
        self.query = '''
            query ProjectsQuery {
              projects {
                    ...ProjectParts                    
              }
            }
            
            fragment ProjectParts on ProjectNode {
              id
              title
              appearance
              description
              slug
              objectives
              __typename
            }
            
        '''

    def test_should_see_own_projects(self):
        self.assertEqual(Project.objects.count(), 1)

        result = self.get_client(self.student1).execute(self.query)

        self.assertIsNone(result.get('errors'))
        self.assertEqual(result.get('data').get('projects')[0].get('title'), self.project1.title)

    def test_should_not_see_other_projects(self):
        self.assertEqual(Project.objects.count(), 1)

        result = self.get_client(self.student2).execute(self.query)

        self.assertIsNone(result.get('errors'))
        self.assertEqual(len(result.get('data').get('projects')), 0)

    def test_teacher_should_not_see_unfinished_projects(self):
        result = self.get_client().execute(self.query)

        self.assertIsNone(result.get('errors'))
        self.assertEqual(len(result.get('data').get('projects')), 0)

    def test_teacher_should_only_see_finished_projects(self):
        self.project1.final = True
        self.project1.save()
        self.assertEqual(Project.objects.count(), 1)

        result = self.get_client().execute(self.query)

        self.assertIsNone(result.get('errors'))
        self.assertEqual(result.get('data').get('projects')[0].get('title'),
                         self.project1.title)

    def test_other_teacher_should_not_see_projects(self):
        self.project1.final = True
        self.project1.save()
        self.assertEqual(Project.objects.count(), 1)

        result = self.get_client(self.teacher2).execute(self.query)

        self.assertIsNone(result.get('errors'))
        self.assertEqual(len(result.get('data').get('projects')), 0)

    def test_direct_project_access(self):
        # student can access own project directly
        self._test_direct_project_access(self.student1, True)
        # teacher can't access project, as it's not final
        self._test_direct_project_access(self.teacher, False)
        self._test_direct_project_access(self.teacher2, False)
        # non-owner can't access project
        self._test_direct_project_access(self.student2, False)


    def test_direct_final_project_access(self):
        self.project1.final = True
        self.project1.save()
        # student can access own project directly
        self._test_direct_project_access(self.student1, True)
        # teacher of student can access project, as it's final
        self._test_direct_project_access(self.teacher, True)
        # other teacher can't access project, as it's not final
        self._test_direct_project_access(self.teacher2, False)
        # non-owner can't access project
        self._test_direct_project_access(self.student2, False)
