# -*- coding: utf-8 -*-
"""
Tests for the ``ProgramEnrollmentView`` view of the Enterprise app.
"""

import copy

import ddt
import mock
from faker import Factory as FakerFactory
from pytest import mark
from six.moves.urllib.parse import urlencode  # pylint: disable=import-error

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpResponse
from django.test import Client, TestCase
from django.urls import reverse

from enterprise.utils import NotConnectedToOpenEdX
from test_utils import fake_render
from test_utils.factories import (
    DataSharingConsentFactory,
    EnterpriseCustomerFactory,
    EnterpriseCustomerIdentityProviderFactory,
    EnterpriseCustomerUserFactory,
    UserFactory,
)
from test_utils.fake_catalog_api import FAKE_PROGRAM_RESPONSE3, setup_course_catalog_api_client_mock
from test_utils.mixins import EmbargoAPIMixin, MessagesMixin


@mark.django_db
@ddt.ddt
class TestProgramEnrollmentView(EmbargoAPIMixin, MessagesMixin, TestCase):
    """
    ProgramEnrollmentView test cases.
    """

    def setUp(self):
        """
        Set up reusable fake data.
        """
        self.user = UserFactory.create(is_staff=True, is_active=True)
        self.user.set_password("QWERTY")
        self.user.save()
        self.client = Client()
        self.demo_course_1 = FAKE_PROGRAM_RESPONSE3['courses'][0]
        self.demo_course_2 = FAKE_PROGRAM_RESPONSE3['courses'][1]
        self.demo_course_id1 = FAKE_PROGRAM_RESPONSE3['courses'][0]['key']
        self.demo_course_id2 = FAKE_PROGRAM_RESPONSE3['courses'][1]['key']
        self.demo_course_ids = [self.demo_course_id1, self.demo_course_id2]
        self.dummy_program_uuid = FAKE_PROGRAM_RESPONSE3['uuid']
        self.dummy_program = FAKE_PROGRAM_RESPONSE3
        super(TestProgramEnrollmentView, self).setUp()

    def _login(self):
        """
        Log the user in.
        """
        assert self.client.login(username=self.user.username, password="QWERTY")

    def _assert_get_returns_404_with_mock(self, url):
        """
        Mock the render method, run a GET, and assert it returns 404.
        """
        with mock.patch('enterprise.views.render') as mock_render:
            mock_render.return_value = HttpResponse()
            self.client.get(url)
            assert mock_render.call_args_list[0][1]['status'] == 404

    def _setup_course_catalog_client(self, client_mock):
        """
        Sets up the Course Catalog API client.
        """
        client = client_mock.return_value
        client.get_program_course_keys.return_value = self.demo_course_ids
        client.get_program_by_uuid.return_value = self.dummy_program

    def _setup_program_data_extender(self, extender_mock, course_overrides=None):
        """
        Sets up the `ProgramDataExtender` mock, a utility from the edx-platform.
        """
        # TODO: Update this mock when we upstream the additional program context from `get_program_details`.
        dummy_program_extended = copy.deepcopy(self.dummy_program)
        dummy_course_extended_1 = copy.deepcopy(self.demo_course_1)
        dummy_course_extended_2 = copy.deepcopy(self.demo_course_2)
        if course_overrides:
            dummy_course_extended_1.update(course_overrides)
            dummy_course_extended_2.update(course_overrides)
        dummy_course_extended_1['course_runs'][0].update({"is_enrolled": False, "upgrade_url": None})
        dummy_course_extended_2['course_runs'][0].update({"is_enrolled": False, "upgrade_url": None})
        dummy_program_extended.update({
            "courses": [
                dummy_course_extended_1,
                dummy_course_extended_2,
            ],
            "discount_data": {
                "currency": "USD",
                "discounted_value": 50,
                "is_discounted": True,
                "total_incl_tax": 250.0,
                "total_incl_tax_excl_discounts": 300.0,
            },
            "full_program_price": 250.0,
            "is_learner_eligible_for_one_click_purchase": True,
            "skus": [
                "sku1",
                "sku2",
            ],
            "variant": "full",
        })
        extender_mock.return_value.extend.return_value = dummy_program_extended
        return extender_mock

    def _setup_registry_mock(self, registry_mock, provider_id):
        """
        Sets up the SSO Registry object.
        """
        registry_mock.get.return_value.configure_mock(provider_id=provider_id)

    def _setup_get_data_sharing_consent(self, client_mock, required):
        """
        Sets up the ``get_data_sharing_consent`` function mock.
        """
        client_mock.return_value.consent_required.return_value = required

    def _setup_get_base_details_mock(
            self,
            client_mock,
            program_details,
            program_enrollment_details
    ):
        """
        Sets up the ``enterprise.views.ProgramEnrollmentView.get_base_details`` function mock.
        """
        client_mock.return_value = (program_details, program_enrollment_details,)

    def _check_expected_enrollment_page(self, response, expected_context):
        """
        Check that the response was successful, and contains the expected content.
        """
        default_context = {}
        default_context.update(expected_context)
        assert response.status_code == 200
        for key, value in default_context.items():
            assert response.context[key] == value  # pylint: disable=no-member

    def test_get_no_patches(self):
        """
        An error is raised when not connected to Open edX for the Program Enrollment View.
        """
        with self.assertRaises(NotConnectedToOpenEdX):
            self._login()
            self.client.get(
                reverse(
                    'enterprise_program_enrollment_page',
                    args=[EnterpriseCustomerFactory().uuid, self.dummy_program_uuid])
            )

    @mock.patch('enterprise.views.render', side_effect=fake_render)
    @mock.patch('enterprise.api_client.lms.embargo_api')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    @mock.patch('enterprise.views.ProgramDataExtender')
    def test_get_program_enrollment_page(
            self,
            program_data_extender_mock,
            course_catalog_api_client_mock,
            embargo_api_mock,
            *args
    ):  # pylint: disable=unused-argument,invalid-name
        """
        The Enterprise Program landing page is rendered appropriately given some context.
        """
        self._setup_embargo_api(embargo_api_mock)
        self._setup_program_data_extender(program_data_extender_mock)
        setup_course_catalog_api_client_mock(course_catalog_api_client_mock)
        enterprise_customer = EnterpriseCustomerFactory(name='Starfleet Academy')
        expected_context = {
            'LMS_SEGMENT_KEY': settings.LMS_SEGMENT_KEY,
            'LMS_ROOT_URL': 'http://lms.example.com',
            'enterprise_customer': enterprise_customer,
            'platform_name': 'Test platform',
            'program_type_logo': 'http://localhost:18381/media/media/program_types/logo_images/'
                                 'professional-certificate.medium.png',
            'platform_description': 'Test description',
            'program_type_description_header': 'What is an Test platform Professional Certificate?',
            'platform_description_header': 'What is Test platform?',
            'tagline': "High-quality online learning opportunities from the world's best universities",
            'header_logo_alt_text': 'Test platform home page',
            'organization_name': 'Authoring Organization',
            'organization_logo': 'images/logo_image_url.jpg',
            'program_type': 'Professional Certificate',
            'program_type_description': 'Designed by industry leaders and top universities to enhance '
                                        'professional skills, Professional Certificates develop the '
                                        'proficiency and expertise that employers are looking for with '
                                        'specialized training and professional education.',
            'page_title': 'Confirm your program enrollment',
            'program_title': 'Program Title 1',
            'program_subtitle': 'Program Subtitle 1',
            'program_overview': 'This is a test Program.',
            'program_price': '$300',
            'program_discounted_price': '$250',
            'is_discounted': True,
            'courses': [
                {
                    "key": 'course-v1:edX+DemoX+Demo_Course',
                    "uuid": "a312ec52-74ef-434b-b848-f110eb90b672",
                    "title": "edX Demonstration Course",
                    'course_title': 'edX Demonstration Course',
                    'course_short_description': 'This course demonstrates many features of the edX platform.',
                    'course_full_description': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
                    'course_image_uri': 'http://edx.devstack.lms:18000/asset-v1:edX+DemoX+Demo_Course+type'
                                        '@asset+block@images_course_image.jpg',
                    'course_level_type': 'Type 1',
                    'weeks_to_complete': '10 weeks',
                    'course_effort': '5-6 hours per week',
                    'staff': [
                        {
                            'uuid': '51df1077-1b8d-4f86-8305-8adbc82b72e9',
                            'given_name': 'Anant',
                            'family_name': 'Agarwal',
                            'bio': "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
                            'profile_image_url': 'https://www.edx.org/sites/default/files/executive/photo/'
                                                 'anant-agarwal.jpg',
                            'slug': 'anant-agarwal',
                            'position': {
                                'title': 'CEO',
                                'organization_name': 'edX'
                            },
                            'profile_image': {},
                            'works': [],
                            'urls': {
                                'twitter': None,
                                'facebook': None,
                                'blog': None
                            },
                            'email': None
                        }
                    ],
                    'expected_learning_items': [
                        'XBlocks',
                        'Peer Assessment',
                    ],
                    "course_runs": [
                        {
                            "key": 'course-v1:edX+DemoX+Demo_Course',
                            "uuid": "a276c25f-c640-4943-98dd-6c9ad8c71bb9",
                            "title": "edX Demonstration Course",
                            "short_description": "",
                            "marketing_url": "course/edxdemo?utm_medium=affiliate_partner&utm_source=staff",
                            "seats": [],
                            "start": "2016-01-01T00:00:00Z",
                            "end": "2018-01-01T00:00:00Z",
                            "enrollment_start": None,
                            "enrollment_end": None,
                            "pacing_type": "self_paced",
                            "type": None,
                            "status": "published",
                            "is_enrolled": False,
                            "upgrade_url": None,
                        },
                    ],
                },
                {
                    "key": 'course-v1:edX+DemoX+Demo_Course2',
                    "uuid": "b312ec52-74ef-434b-b848-f110eb90b672",
                    "title": "edX Demonstration Course 2",
                    'course_title': 'edX Demonstration Course',
                    'course_short_description': 'This course demonstrates many features of the edX platform.',
                    'course_full_description': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
                    'course_image_uri': 'http://edx.devstack.lms:18000/asset-v1:edX+DemoX+Demo_Course+type'
                                        '@asset+block@images_course_image.jpg',
                    'course_level_type': 'Type 1',
                    'course_effort': '5-6 hours per week',
                    'weeks_to_complete': '10 weeks',
                    'staff': [
                        {
                            'uuid': '51df1077-1b8d-4f86-8305-8adbc82b72e9',
                            'given_name': 'Anant',
                            'family_name': 'Agarwal',
                            'bio': "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
                            'profile_image_url': 'https://www.edx.org/sites/default/files/executive/photo/'
                                                 'anant-agarwal.jpg',
                            'slug': 'anant-agarwal',
                            'position': {
                                'title': 'CEO',
                                'organization_name': 'edX'
                            },
                            'profile_image': {},
                            'works': [],
                            'urls': {
                                'twitter': None,
                                'facebook': None,
                                'blog': None
                            },
                            'email': None
                        }
                    ],
                    'expected_learning_items': [
                        'XBlocks',
                        'Peer Assessment',
                    ],
                    "course_runs": [
                        {
                            "key": 'course-v1:edX+DemoX+Demo_Course2',
                            "uuid": "b276c25f-c640-4943-98dd-6c9ad8c71bb9",
                            "title": "edX Demonstration Course 2",
                            "short_description": "",
                            "marketing_url": "course/edxdemo?utm_medium=affiliate_partner&utm_source=staff",
                            "seats": [],
                            "start": "2016-01-01T00:00:00Z",
                            "end": "2018-01-01T00:00:00Z",
                            "enrollment_start": None,
                            "enrollment_end": None,
                            "pacing_type": "self_paced",
                            "type": None,
                            "status": "published",
                            "is_enrolled": False,
                            "upgrade_url": None,
                        },
                    ],
                },
            ],
            'purchase_text': 'Pursue the program for',
            'course_count_text': '2 Courses',
            'item_bullet_points': [
                'Credit- and Certificate-eligible',
                'Self-paced; courses can be taken in any order',
            ],
            'enrolled_in_course_and_paid_text': 'enrolled',
            'enrolled_in_course_and_unpaid_text': 'already enrolled, must pay for certificate',
            'expected_learning_items_text': "What you'll learn",
            'expected_learning_items': [
                "Blocks",
                "XBlocks",
                "Peer Assessment"
            ],
            'expected_learning_items_show_count': 2,
            'corporate_endorsements_text': 'Real Career Impact',
            'corporate_endorsements': [
                {
                    "corporation_name": "Bob's Company",
                    "statement": "",
                    "image": {
                        "src": "http://evonexus.org/wp-content/uploads/2016/01/IBM-logo-1024x576.jpg",
                        "description": None,
                        "height": None,
                        "width": None,
                    },
                    "individual_endorsements": [
                        {
                            "endorser": {
                                "uuid": "789aa881-e44b-4675-9377-fa103c12bbfc",
                                "given_name": "Bob",
                                "family_name": "the Builder",
                                "bio": "Working hard on a daily basis!",
                                "profile_image_url": None,
                                "slug": "bob-the-builder",
                                "position": {
                                    "title": "Engineer",
                                    "organization_name": "Bob's Company",
                                    "organization_id": 1
                                },
                                "profile_image": {},
                                "works": [],
                                "urls": {
                                    "facebook": None,
                                    "twitter": None,
                                    "blog": None,
                                },
                                "email": None
                            },
                            "quote": "Life is hard for us engineers. Period."
                        }
                    ]
                }
            ],
            'corporate_endorsements_show_count': 1,
            'see_more_text': 'See More',
            'see_less_text': 'See Less',
            'confirm_button_text': 'Confirm Program',
            'summary_header': 'Program Summary',
            'price_text': 'Price',
            'length_text': 'Length',
            'length_info_text': '4-6 weeks per course',
            'effort_text': 'Effort',
            'effort_info_text': '5-10 hours per week, per course',
            'program_not_eligible_for_one_click_purchase_text': 'Program not eligible for one-click purchase.',
            'level_text': 'Level',
            'course_full_description_text': 'About This Course',
            'staff_text': 'Course Staff',
            'close_modal_button_text': 'Close',
            'is_learner_eligible_for_one_click_purchase': True,
        }
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        response = self.client.get(program_enrollment_page_url)
        self._check_expected_enrollment_page(response, expected_context)

    @mock.patch('enterprise.views.render', side_effect=fake_render)
    @mock.patch('enterprise.api_client.lms.embargo_api')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    @mock.patch('enterprise.views.ProgramDataExtender')
    def test_get_program_enrollment_page_enrolled_in_program(
            self,
            program_data_extender_mock,
            course_catalog_api_client_mock,
            embargo_api_mock,
            *args
    ):  # pylint: disable=unused-argument,invalid-name
        """
        The Enterprise Program landing page is rendered appropriately given that the user is enrolled in the program.
        """
        self._setup_embargo_api(embargo_api_mock)
        program_data_extender_mock = self._setup_program_data_extender(program_data_extender_mock)
        program_data_extender_mock.return_value.extend.return_value['courses'][0]['course_runs'][0].update({
            "is_enrolled": True,
            "upgrade_url": None,
        })
        setup_course_catalog_api_client_mock(course_catalog_api_client_mock)
        enterprise_customer = EnterpriseCustomerFactory(name='Starfleet Academy')
        expected_context = {
            'page_title': 'Confirm your enrollment',
            'purchase_text': 'Purchase all unenrolled courses for',
            'courses': [
                {
                    "key": 'course-v1:edX+DemoX+Demo_Course',
                    "uuid": "a312ec52-74ef-434b-b848-f110eb90b672",
                    "title": "edX Demonstration Course",
                    'course_title': 'edX Demonstration Course',
                    'course_short_description': 'This course demonstrates many features of the edX platform.',
                    'course_full_description': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
                    'course_image_uri': 'http://edx.devstack.lms:18000/asset-v1:edX+DemoX+Demo_Course+type'
                                        '@asset+block@images_course_image.jpg',
                    'course_level_type': 'Type 1',
                    'course_effort': '5-6 hours per week',
                    'weeks_to_complete': '10 weeks',
                    'staff': [
                        {
                            'uuid': '51df1077-1b8d-4f86-8305-8adbc82b72e9',
                            'given_name': 'Anant',
                            'family_name': 'Agarwal',
                            'bio': "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
                            'profile_image_url': 'https://www.edx.org/sites/default/files/executive/photo/'
                                                 'anant-agarwal.jpg',
                            'slug': 'anant-agarwal',
                            'position': {
                                'title': 'CEO',
                                'organization_name': 'edX'
                            },
                            'profile_image': {},
                            'works': [],
                            'urls': {
                                'twitter': None,
                                'facebook': None,
                                'blog': None
                            },
                            'email': None
                        }
                    ],
                    'expected_learning_items': [
                        'XBlocks',
                        'Peer Assessment',
                    ],
                    "course_runs": [
                        {
                            "key": 'course-v1:edX+DemoX+Demo_Course',
                            "uuid": "a276c25f-c640-4943-98dd-6c9ad8c71bb9",
                            "title": "edX Demonstration Course",
                            "short_description": "",
                            "marketing_url": "course/edxdemo?utm_medium=affiliate_partner&utm_source=staff",
                            "seats": [],
                            "start": "2016-01-01T00:00:00Z",
                            "end": "2018-01-01T00:00:00Z",
                            "enrollment_start": None,
                            "enrollment_end": None,
                            "pacing_type": "self_paced",
                            "type": None,
                            "status": "published",
                            "is_enrolled": True,
                            "upgrade_url": None,
                        },
                    ],
                },
                {
                    "key": 'course-v1:edX+DemoX+Demo_Course2',
                    "uuid": "b312ec52-74ef-434b-b848-f110eb90b672",
                    "title": "edX Demonstration Course 2",
                    'course_title': 'edX Demonstration Course',
                    'course_short_description': 'This course demonstrates many features of the edX platform.',
                    'course_full_description': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
                    'course_image_uri': 'http://edx.devstack.lms:18000/asset-v1:edX+DemoX+Demo_Course+type'
                                        '@asset+block@images_course_image.jpg',
                    'course_level_type': 'Type 1',
                    'course_effort': '5-6 hours per week',
                    'weeks_to_complete': '10 weeks',
                    'staff': [
                        {
                            'uuid': '51df1077-1b8d-4f86-8305-8adbc82b72e9',
                            'given_name': 'Anant',
                            'family_name': 'Agarwal',
                            'bio': "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
                            'profile_image_url': 'https://www.edx.org/sites/default/files/executive/photo/'
                                                 'anant-agarwal.jpg',
                            'slug': 'anant-agarwal',
                            'position': {
                                'title': 'CEO',
                                'organization_name': 'edX'
                            },
                            'profile_image': {},
                            'works': [],
                            'urls': {
                                'twitter': None,
                                'facebook': None,
                                'blog': None
                            },
                            'email': None
                        }
                    ],
                    'expected_learning_items': [
                        'XBlocks',
                        'Peer Assessment',
                    ],
                    "course_runs": [
                        {
                            "key": 'course-v1:edX+DemoX+Demo_Course2',
                            "uuid": "b276c25f-c640-4943-98dd-6c9ad8c71bb9",
                            "title": "edX Demonstration Course 2",
                            "short_description": "",
                            "marketing_url": "course/edxdemo?utm_medium=affiliate_partner&utm_source=staff",
                            "seats": [],
                            "start": "2016-01-01T00:00:00Z",
                            "end": "2018-01-01T00:00:00Z",
                            "enrollment_start": None,
                            "enrollment_end": None,
                            "pacing_type": "self_paced",
                            "type": None,
                            "status": "published",
                            "is_enrolled": False,
                            "upgrade_url": None,
                        },
                    ],
                },
            ],
        }
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        response = self.client.get(program_enrollment_page_url)
        self._check_expected_enrollment_page(response, expected_context)

    @mock.patch('enterprise.views.render', side_effect=fake_render)
    @mock.patch('enterprise.api_client.lms.embargo_api')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    @mock.patch('enterprise.views.ProgramDataExtender')
    @ddt.data(True, False)
    def test_get_program_enrollment_page_consent_message(
            self,
            consent_granted,
            program_data_extender_mock,
            course_catalog_api_client_mock,
            embargo_api_mock,
            *args
    ):  # pylint: disable=unused-argument,invalid-name
        """
        The DSC-declined message is rendered if DSC is not given.
        """
        self._setup_embargo_api(embargo_api_mock)
        self._setup_program_data_extender(program_data_extender_mock)
        setup_course_catalog_api_client_mock(course_catalog_api_client_mock)
        enterprise_customer = EnterpriseCustomerFactory(name='Starfleet Academy')
        enterprise_customer_user = EnterpriseCustomerUserFactory(
            enterprise_customer=enterprise_customer,
            user_id=self.user.id
        )
        for dummy_course_id in self.demo_course_ids:
            DataSharingConsentFactory(
                course_id=dummy_course_id,
                granted=consent_granted,
                enterprise_customer=enterprise_customer,
                username=enterprise_customer_user.username,
            )
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        response = self.client.get(program_enrollment_page_url)
        messages = self._get_messages_from_response_cookies(response)
        if consent_granted:
            assert not messages
        else:
            assert messages
            self._assert_request_message(
                messages[0],
                'warning',
                (
                    '<strong>We could not enroll you in <em>Program Title 1</em>.</strong> '
                    '<span>If you have questions or concerns about sharing your data, please '
                    'contact your learning manager at Starfleet Academy, or contact '
                    '<a href="{enterprise_support_link}" target="_blank">{platform_name} support</a>.</span>'
                ).format(
                    enterprise_support_link=settings.ENTERPRISE_SUPPORT_URL,
                    platform_name=settings.PLATFORM_NAME,
                )
            )

    @mock.patch('enterprise.views.render', side_effect=fake_render)
    @mock.patch('enterprise.api_client.lms.embargo_api')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    @mock.patch('enterprise.views.ProgramDataExtender')
    def test_get_program_enrollment_page_no_price_info_found_message(
            self,
            program_data_extender_mock,
            course_catalog_api_client_mock,
            embargo_api_mock,
            *args
    ):  # pylint: disable=unused-argument,invalid-name
        """
        The message about no price information found is rendered if the program extender fails to get price info.
        """
        self._setup_embargo_api(embargo_api_mock)
        program_data_extender_mock = self._setup_program_data_extender(program_data_extender_mock)
        program_data_extender_mock.return_value.extend.return_value['discount_data'] = {}
        setup_course_catalog_api_client_mock(course_catalog_api_client_mock)
        enterprise_customer = EnterpriseCustomerFactory(name='Starfleet Academy')
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        response = self.client.get(program_enrollment_page_url)
        messages = self._get_messages_from_response_cookies(response)
        assert messages
        self._assert_request_message(
            messages[0],
            'warning',
            (
                '<strong>We could not gather price information for <em>Program Title 1</em>.</strong> '
                '<span>If you continue to have these issues, please contact '
                '<a href="{enterprise_support_link}" target="_blank">{platform_name} support</a>.</span>'
            ).format(
                enterprise_support_link=settings.ENTERPRISE_SUPPORT_URL,
                platform_name=settings.PLATFORM_NAME,
            )
        )

    @mock.patch('enterprise.views.render', side_effect=fake_render)
    @mock.patch('enterprise.api_client.lms.embargo_api')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    @mock.patch('enterprise.views.ProgramDataExtender')
    @ddt.data(True, False)
    def test_get_program_enrollment_page_program_unenrollable(
            self,
            enrollable,
            program_data_extender_mock,
            course_catalog_api_client_mock,
            embargo_api_mock,
            *args
    ):  # pylint: disable=unused-argument,invalid-name
        """
        The message about the program being unenrollable is displayed.
        """
        self._setup_embargo_api(embargo_api_mock)
        program_data_extender_mock = self._setup_program_data_extender(program_data_extender_mock).return_value
        program_data_extender_mock.extend.return_value['is_learner_eligible_for_one_click_purchase'] = enrollable
        setup_course_catalog_api_client_mock(course_catalog_api_client_mock)
        enterprise_customer = EnterpriseCustomerFactory(name='Starfleet Academy')
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        response = self.client.get(program_enrollment_page_url)
        messages = self._get_messages_from_response_cookies(response)
        if enrollable:
            assert not messages
        else:
            assert messages
            self._assert_request_message(
                messages[0],
                'info',
                (
                    '<strong>Something happened.</strong> '
                    '<span>This program is not currently open to new learners. '
                    'Please start over and select a different program.</span>'
                )
            )

    @mock.patch('enterprise.api_client.lms.embargo_api')
    @mock.patch('enterprise.views.ProgramDataExtender')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    def test_get_program_enrollment_page_for_non_existing_program(
            self,
            course_catalog_api_client_mock,
            embargo_api_mock,
            *args
    ):  # pylint: disable=unused-argument
        """
        The user will see the HTTP 404 (Not Found) page in case of an invalid or non existing program.
        """
        self._setup_embargo_api(embargo_api_mock)
        course_catalog_api_client_mock.return_value.get_program_by_uuid.return_value = None
        enterprise_customer = EnterpriseCustomerFactory()
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        self._assert_get_returns_404_with_mock(program_enrollment_page_url)

    @mock.patch('enterprise.api_client.lms.embargo_api')
    @mock.patch('enterprise.views.ProgramDataExtender')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    def test_get_program_enrollment_page_for_non_existing_program_type(
            self,
            course_catalog_api_client_mock,
            embargo_api_mock,
            *args
    ):  # pylint: disable=unused-argument
        """
        The user will see the HTTP 404 (Not Found) page in case of an invalid or non existing program type.
        """
        self._setup_embargo_api(embargo_api_mock)
        course_catalog_api_client_mock.return_value.get_program_type_by_slug.return_value = None
        enterprise_customer = EnterpriseCustomerFactory()
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        self._assert_get_returns_404_with_mock(program_enrollment_page_url)

    def test_get_program_enrollment_page_for_invalid_ec_uuid(self):
        """
        The user will see the HTTP 404 (Not Found) page in case of an invalid enterprise customer UUID.
        """
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=['some-fake-enterprise-customer-uuid', self.dummy_program_uuid],
        )

        self._login()
        response = self.client.get(program_enrollment_page_url)
        assert response.status_code == 404

    @mock.patch('enterprise.views.ProgramDataExtender')
    def test_get_program_enrollment_page_for_nonexisting_ec(self, *args):  # pylint: disable=unused-argument
        """
        The user will see the HTTP 404 (Not Found) page in case of no matching ``EnterpriseCustomer``.
        """
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=['9f9093b0-58e9-480c-a619-5af5000507bb', self.dummy_program_uuid],
        )

        self._login()
        response = self.client.get(program_enrollment_page_url)
        assert response.status_code == 404

    @mock.patch('enterprise.views.ProgramDataExtender')
    @mock.patch('enterprise.utils.Registry')
    def test_get_program_enrollment_page_for_inactive_user(
            self,
            registry_mock,
            *args
    ):  # pylint: disable=unused-argument
        """
        The user is redirected to the login screen to sign in with an enterprise-linked SSO when inactive.
        """
        enterprise_customer = EnterpriseCustomerFactory()
        faker = FakerFactory.create()
        provider_id = faker.slug()  # pylint: disable=no-member
        self._setup_registry_mock(registry_mock, provider_id)
        EnterpriseCustomerIdentityProviderFactory(provider_id=provider_id, enterprise_customer=enterprise_customer)
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        response = self.client.get(program_enrollment_page_url)
        expected_base_url = (
            '/login?next=%2Fenterprise%2F{enterprise_customer_uuid}%2F'
            'program%2F{program_uuid}%2Fenroll%2F'
        ).format(
            enterprise_customer_uuid=enterprise_customer.uuid,
            program_uuid=self.dummy_program_uuid
        )
        expected_fragments = (
            'tpa_hint%3D{provider_id}'.format(
                provider_id=provider_id,
            ),
            'new_enterprise_login%3Dyes'
        )
        assert response.status_code == 302
        assert expected_base_url in response.url
        for fragment in expected_fragments:
            assert fragment in response.url

    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    @mock.patch('enterprise.views.ProgramDataExtender')
    def test_get_program_enrollment_page_for_certificate_eligible_user(
            self,
            program_data_extender_mock,
            course_catalog_api_client_mock,
            *args
    ):  # pylint: disable=unused-argument,invalid-name
        """
        The user will be redirected to the program's dashboard when already certificate-eligible for the program.
        """
        program_data_extender_mock = self._setup_program_data_extender(program_data_extender_mock)
        for course in program_data_extender_mock.return_value.extend.return_value['courses']:
            course['course_runs'][0].update({
                "is_enrolled": True,
                "upgrade_url": None,
            })
        setup_course_catalog_api_client_mock(course_catalog_api_client_mock)
        enterprise_customer = EnterpriseCustomerFactory()
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        response = self.client.get(program_enrollment_page_url)
        self.assertRedirects(
            response,
            'http://lms.example.com/dashboard/programs/{program_uuid}'.format(program_uuid=self.dummy_program_uuid),
            fetch_redirect_response=False,
        )

    @mock.patch('enterprise.views.ProgramDataExtender')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    def test_get_program_enrollment_page_with_discovery_error(
            self,
            course_catalog_api_client_mock,
            *args
    ):  # pylint: disable=unused-argument
        """
        We raise a 404 when there are Discovery API-related errors.
        """
        course_catalog_api_client_mock.side_effect = ImproperlyConfigured
        enterprise_customer = EnterpriseCustomerFactory()
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        self._assert_get_returns_404_with_mock(program_enrollment_page_url)

    @mock.patch('enterprise.views.ProgramDataExtender')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    def test_post_program_enrollment_view_redirect_to_program_dashboard(
            self,
            course_catalog_api_client_mock,
            program_data_extender_mock,
            *args
    ):  # pylint: disable=unused-argument,invalid-name
        """
        The user is redirected to the program dashboard on POST if already certificate eligible for the program.
        """
        program_data_extender_mock = self._setup_program_data_extender(program_data_extender_mock)
        for course in program_data_extender_mock.return_value.extend.return_value['courses']:
            course['course_runs'][0].update({
                "is_enrolled": True,
                "upgrade_url": None,
            })
        setup_course_catalog_api_client_mock(course_catalog_api_client_mock)
        enterprise_customer = EnterpriseCustomerFactory()
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        response = self.client.post(program_enrollment_page_url)
        assert response.status_code == 302
        self.assertRedirects(
            response,
            'http://lms.example.com/dashboard/programs/52ad909b-c57d-4ff1-bab3-999813a2479b',
            fetch_redirect_response=False
        )

    @mock.patch('enterprise.views.get_data_sharing_consent')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    @mock.patch('enterprise.views.ProgramDataExtender')
    def test_post_program_enrollment_view_redirect_to_dsc(
            self,
            program_data_extender_mock,
            course_catalog_api_client_mock,
            get_dsc_mock,
            *args
    ):  # pylint: disable=unused-argument
        """
        The user is redirected to the DSC page when DSC is needed.
        """
        self._setup_program_data_extender(program_data_extender_mock)
        setup_course_catalog_api_client_mock(course_catalog_api_client_mock)
        self._setup_get_data_sharing_consent(get_dsc_mock, required=True)
        enterprise_customer = EnterpriseCustomerFactory()
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        response = self.client.post(program_enrollment_page_url)
        assert response.status_code == 302
        self.assertRedirects(
            response,
            '/enterprise/grant_data_sharing_permissions?{}'.format(
                urlencode(
                    {
                        'next': 'http://localhost:18130/basket/add/?sku=sku1&sku=sku2'
                                '&bundle=52ad909b-c57d-4ff1-bab3-999813a2479b',
                        'failure_url': program_enrollment_page_url,
                        'enterprise_customer_uuid': enterprise_customer.uuid,
                        'program_uuid': self.dummy_program_uuid,
                    }
                )
            ),
            fetch_redirect_response=False
        )

    @mock.patch('enterprise.views.get_data_sharing_consent')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    @mock.patch('enterprise.views.ProgramDataExtender')
    def test_post_program_enrollment_view_redirect_to_basket(
            self,
            program_data_extender_mock,
            course_catalog_api_client_mock,
            get_dsc_mock,
            *args
    ):  # pylint: disable=unused-argument
        """
        The user is redirected to the basket page when something needs to be bought.
        """
        self._setup_program_data_extender(program_data_extender_mock)
        setup_course_catalog_api_client_mock(course_catalog_api_client_mock)
        self._setup_get_data_sharing_consent(get_dsc_mock, required=False)
        enterprise_customer = EnterpriseCustomerFactory()
        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        response = self.client.post(program_enrollment_page_url)
        assert response.status_code == 302
        self.assertRedirects(
            response,
            'http://localhost:18130/basket/add/?sku=sku1&sku=sku2&bundle=52ad909b-c57d-4ff1-bab3-999813a2479b',
            fetch_redirect_response=False
        )

    @mock.patch('enterprise.views.render', side_effect=fake_render)
    @mock.patch('enterprise.api_client.lms.embargo_api')
    @mock.patch('enterprise.api_client.discovery.CourseCatalogApiServiceClient')
    @mock.patch('enterprise.views.ProgramDataExtender')
    def test_embargo_restriction(
            self,
            program_data_extender_mock,
            course_catalog_api_client_mock,
            embargo_api_mock,
            *args
    ):  # pylint: disable=unused-argument,invalid-name
        """
        The Enterprise Program landing page is rendered appropriately given some context.
        """
        self._setup_embargo_api(embargo_api_mock, redirect_url=self.EMBARGO_REDIRECT_URL)
        self._setup_program_data_extender(program_data_extender_mock)
        setup_course_catalog_api_client_mock(course_catalog_api_client_mock)
        enterprise_customer = EnterpriseCustomerFactory(name='Starfleet Academy')

        program_enrollment_page_url = reverse(
            'enterprise_program_enrollment_page',
            args=[enterprise_customer.uuid, self.dummy_program_uuid],
        )

        self._login()
        response = self.client.get(program_enrollment_page_url)
        assert response.status_code == 302
        self.assertRedirects(
            response,
            self.EMBARGO_REDIRECT_URL,
            fetch_redirect_response=False
        )