def post(self):
        """
        Creates a recommendation
        This endpoint will create a Recommendation based the data that is posted

        """
        app.logger.info(
            "Request for create a new recommendation in the database")

        app.logger.debug('Payload = %s', api.payload)
        recommendation = Recommendation()
        try:
            recommendation.deserialize(api.payload)
        except DataValidationError as error:
            raise BadRequest("Bad Request invalid data payload")

        if recommendation.product_id == recommendation.related_product_id:
            raise BadRequest(
                "product_id cannot be the same as related_product_id")

        existing_recommendation = (Recommendation.find_recommendation(
            recommendation.product_id,
            recommendation.related_product_id).first()
                                   or Recommendation.find_recommendation(
                                       recommendation.product_id,
                                       recommendation.related_product_id,
                                       by_status=False,
                                   ).first())

        if existing_recommendation:
            raise BadRequest(
                "Recommendation with given product id and related product id already exists"
            )

        recommendation.create()
        location_url = api.url_for(
            RecommendationResource,
            product_id=recommendation.product_id,
            related_product_id=recommendation.related_product_id,
            _external=True)

        app.logger.info(
            "recommendation from product ID [%s] to related product ID [%s] created.",
            recommendation.product_id,
            recommendation.related_product_id,
        )
        return (recommendation.serialize(), status.HTTP_201_CREATED, {
            "location": location_url
        })
    def test_get_recommendation(self):
        """ Get Recommendation Tests"""
        recommendation = self._create_recommendations(1)[0][0]

        # Test Case 1
        resp = self.app.get(
            BASE_URL
            + "/"
            + str(recommendation.product_id)
            + "/"
            + str(recommendation.related_product_id)
        )

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp.get_json())

        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 2
        resp = self.app.get(
            BASE_URL + "/" + str(recommendation.product_id) + "/" + str(99999)
        )

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        # Test Case 3
        resp = self.app.get(
            BASE_URL + "/" + str(recommendation.product_id) + "/" + str(-99999)
        )

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        # Test Case 4
        resp = self.app.get(BASE_URL + "/" + str(recommendation.product_id) + "/abcd")

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
    def test_toggle_recommendation_between_products(self):
        """ Toggle Recommendations Tests """
        recommendation = self._create_recommendations(count=1, by_status=True)[0][0]
        # Test Case 1
        resp = self.app.put(
            BASE_URL
            + "/{}/{}/toggle".format(
                recommendation.product_id, recommendation.related_product_id
            )
        )
        resp_message = resp.get_json()

        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(resp_message)
        self.assertEqual(not recommendation.status, resp_message["status"])

        resp = self.app.get(
            BASE_URL
            + "/{}/{}".format(
                recommendation.product_id, recommendation.related_product_id
            )
        )
        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp.get_json())

        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertEqual(not recommendation.status, returned_recommendation.status)

        # Test Case 2
        resp = self.app.put(
            BASE_URL
            + "/{}/{}/toggle".format(
                recommendation.product_id, recommendation.related_product_id
            )
        )
        resp_message = resp.get_json()

        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(resp_message)
        self.assertEqual(recommendation.status, resp_message["status"])

        resp = self.app.get(
            BASE_URL
            + "/{}/{}".format(
                recommendation.product_id, recommendation.related_product_id
            )
        )
        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp.get_json())

        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertEqual(recommendation.status, returned_recommendation.status)

        # Test Case 3
        resp = self.app.put(
            BASE_URL
            + "/{}/{}/toggle".format(recommendation.product_id, 99999)
        )

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        # Test Case 4
        resp = self.app.put(
            BASE_URL
            + "/{}/{}/toggle".format(recommendation.product_id, -99999)
        )

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        # Test Case 5
        resp = self.app.put(
            BASE_URL
            + "/{}/{}/toggle".format(recommendation.product_id, "abcd")
        )

        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
    def test_update_recommendation(self):
        """ Update Recommendations Tests """
        recommendations = self._create_recommendations(count=2, by_status=True)
        new_typeid = {1: 2, 2: 3, 3: 1}

        old_recommendation = recommendations[0][0]

        new_recommendation = Recommendation()
        new_recommendation.product_id = old_recommendation.product_id
        new_recommendation.related_product_id = old_recommendation.related_product_id
        new_recommendation.type_id = new_typeid[old_recommendation.type_id]
        new_recommendation.status = True

        update_url = (
           BASE_URL + "/"
            + str(new_recommendation.product_id)
            + "/"
            + str(new_recommendation.related_product_id)
        )
        get_url = (
           BASE_URL + "/"
            + str(old_recommendation.product_id)
            + "/"
            + str(new_recommendation.related_product_id)
        )

        update_resp = self.app.put(
            update_url,
            json=new_recommendation.serialize(),
            content_type="application/json",
        )
        self.assertEqual(update_resp.status_code, status.HTTP_200_OK)
        self.assertNotEqual(len(update_resp.data), 0)

        resp = self.app.get(
            get_url
        )

        self.assertEqual(len(resp.data), len(update_resp.data))
        updated_recommendation = Recommendation()
        updated_recommendation.deserialize(resp.get_json())
        self.assertEqual(
            updated_recommendation,
            new_recommendation,
            "recommendation updated successfully",
        )

        resp = self.app.put(
            update_url, json=new_recommendation.serialize(), content_type="not/json"
        )
        self.assertEqual(resp.status_code, status.HTTP_415_UNSUPPORTED_MEDIA_TYPE)


        old_recommendation = recommendations[1][0]

        # Test invalid product_id
        invalid_recommendation = {
            "product-id": "invalid_id",
            "related-product-id": old_recommendation.related_product_id,
            "type-id": new_typeid[old_recommendation.type_id],
            "status": True,
        }

        update_url = (
           BASE_URL + "/"
            + str(invalid_recommendation["product-id"])
            + "/"
            + str(invalid_recommendation["related-product-id"])
        )
        get_url = (
           BASE_URL + "/"
            + str(old_recommendation.product_id)
            + "/"
            + str(old_recommendation.related_product_id)
        )

        resp = self.app.put(
            update_url, json=invalid_recommendation, content_type="application/json"
        )
        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        resp = self.app.get(
            get_url
        )
        updated_recommendation = Recommendation()
        updated_recommendation.deserialize(resp.get_json())

        self.assertEqual(
            updated_recommendation,
            old_recommendation,
            "recommendation should not be updated",
        )

        # Test invalid related_product_id
        invalid_recommendation = {
            "product-id": old_recommendation.product_id,
            "related-product-id": "invalid_related_product_id",
            "type-id": new_typeid[old_recommendation.type_id],
            "status": True,
        }

        update_url = (
           BASE_URL + "/"
            + str(invalid_recommendation["product-id"])
            + "/"
            + str(invalid_recommendation["related-product-id"])
        )

        resp = self.app.put(
            update_url, json=invalid_recommendation, content_type="application/json"
        )
        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)

        # Test invalid type
        invalid_recommendation = {
            "product-id": old_recommendation.product_id,
            "related-product-id": old_recommendation.related_product_id,
            "type-id": 10,
            "status": True,
        }

        update_url = (
           BASE_URL + "/"
            + str(invalid_recommendation["product-id"])
            + "/"
            + str(invalid_recommendation["related-product-id"])
        )

        resp = self.app.put(
            update_url, json=invalid_recommendation, content_type="application/json"
        )
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)

        # Test non-existe product_id
        non_exist_recommendation = {
            "product-id": 50000,
            "related-product-id": old_recommendation.related_product_id,
            "type-id": 2,
            "status": True,
        }

        update_url = (
           BASE_URL + "/"
            + str(non_exist_recommendation["product-id"])
            + "/"
            + str(non_exist_recommendation["related-product-id"])
        )

        resp = self.app.put(
            update_url, json=non_exist_recommendation, content_type="application/json"
        )
        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
    def test_get_all_recommendations(self):
        """ Get all recommendations tests"""
        # Test Case 1
        # Test for empty database
        resp = self.app.get(BASE_URL)
        self.assertEqual(resp.status_code, status.HTTP_200_OK)

        # Test Case 2
        # Test for non-empty database
        recommendation = self._create_one_recommendation(
            by_id=1, by_rel_id=2, by_type=1
        )[0]

        resp = self.app.get(BASE_URL)
        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertTrue(len(resp.get_json()) > 0)

        # Test for the accuracy
        resp = resp.get_json()
        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp[0])
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 3
        resp = self.app.get(
            BASE_URL + "?product-id={}&related-product-id={}".format(
                recommendation.product_id, recommendation.related_product_id
            )
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 4
        resp = self.app.get(
            BASE_URL + "?product-id={}".format(recommendation.product_id)
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 5
        resp = self.app.get(
            BASE_URL + "?product-id={}".format("test")
        )
        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)

        # Test Case 6
        resp = self.app.get(
            BASE_URL + "?product-id={}&type-id={}".format(
                recommendation.product_id, recommendation.type_id
            )
        )
        resp = resp.get_json()[0]
        
        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        
        # if the type-id is invalid
        resp = self.app.get(BASE_URL + "?product-id={}&type-id={}".format(recommendation.product_id,10))
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
        

        # Test Case 6 
        resp = self.app.get(
            BASE_URL + "?product-id={}&status={}".format(
                recommendation.product_id, recommendation.status
            )
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 7
        resp = self.app.get(
            BASE_URL + "?product-id={}&type-id={}&status={}".format(
                recommendation.product_id, recommendation.type_id, recommendation.status
            )
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)


        # if the type-id is invalid
        resp = self.app.get(BASE_URL + "?product-id={}&type-id={}&status={}".format(
            recommendation.product_id,10, recommendation.status))
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
        

        # Test Case 8
        resp = self.app.get(
            BASE_URL + "?type-id={}&status={}".format(
                recommendation.type_id, recommendation.status
            )
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # if the type-id is invalid
        resp = self.app.get(BASE_URL + "?type-id={}&status={}".format(
            10, recommendation.status))
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
        

        # Test Case 9
        resp = self.app.get(
            BASE_URL + "?type-id={}".format(recommendation.type_id)
        )
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # if the type-id is invalid
        resp = self.app.get(BASE_URL + "?type-id={}".format(10))
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
        


        # Test Case 10
        resp = self.app.get(
            BASE_URL + "?status={}".format(recommendation.status))
        
        resp = resp.get_json()[0]

        returned_recommendation = Recommendation()
        returned_recommendation.deserialize(resp)
        self.assertEqual(recommendation, returned_recommendation)

        # Test Case 11
        resp = self.app.get(
            BASE_URL + "?product-id={}&type-id={}&status={}".format(
                "invalid_product_id", recommendation.type_id, recommendation.status
            )
        )
        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)

        # Test Case 12
        resp = self.app.get(
            BASE_URL + "?product-id={}&type-id={}&status={}".format(
                recommendation.product_id, 5, recommendation.status
            )
        )
        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)

        # Test Case 13
        resp = self.app.get(
            BASE_URL + "?product-id={}&related-product-id={}".format(1,1)
        )
        self.assertEqual(status.HTTP_400_BAD_REQUEST, resp.status_code)