#!/usr/bin/env python
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Creates a rule-based user list.

The list will be defined by a combination of rules for users who have visited
two different pages of a website.
"""

import argparse
import sys
from uuid import uuid4

from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException


# [START add_combined_rule_user_list]
def main(client, customer_id):
    """Creates a rule-based user list.

    The list will be defined by a combination of rules for users who have
    visited two different pages of a website.

    Args:
        client: The Google Ads client.
        customer_id: The customer ID for which to add the user list.
    """
    # Get the UserListService client.
    user_list_service = client.get_service("UserListService")

    rule_infos = []

    # Create rules targeting any user that visits "http://example.com/example1"
    # and "http://example.com/example2".
    for url in ["http://example.com/example1", "http://example.com/example2"]:
        rule_infos.append(_build_visited_site_rule_info(client, url))

    # The two rules are combined by joining the first AND second URLs. See
    # https://developers.google.com/google-ads/api/reference/rpc/latest/CombinedRuleUserListInfo
    # for more details.
    # This rule will create a user list where "Visitors of a page who did visit
    # another page". To create a user list where "Visitors of a page who did not
    # visit another page", change the UserListCombinedRuleOperator from AND to
    # AND_NOT.
    combined_rule_user_list_info = client.get_type("CombinedRuleUserListInfo")
    client.copy_from(combined_rule_user_list_info.left_operand, rule_infos[0])
    client.copy_from(combined_rule_user_list_info.right_operand, rule_infos[1])
    combined_rule_user_list_info.rule_operator = (
        client.enums.UserListCombinedRuleOperatorEnum.AND
    )

    # Define a representation of a user list that is generated by a rule.
    rule_based_user_list_info = client.get_type("RuleBasedUserListInfo")
    # Optional: To include past users in the user list, set the
    # prepopulation_status to REQUESTED.
    rule_based_user_list_info.prepopulation_status = (
        client.enums.UserListPrepopulationStatusEnum.REQUESTED
    )
    client.copy_from(
        rule_based_user_list_info.combined_rule_user_list,
        combined_rule_user_list_info,
    )

    # Create a UserListOperation and populate the UserList.
    user_list_operation = client.get_type("UserListOperation")
    user_list = user_list_operation.create
    user_list.name = (
        "All visitors to http://example.com/example1 AND "
        f"http://example.com/example2 #{uuid4()}"
    )
    user_list.description = (
        "Visitors of both http://example.com/example1 AND "
        "http://example.com/example2"
    )
    user_list.membership_status = client.enums.UserListMembershipStatusEnum.OPEN
    user_list.membership_life_span = 365
    client.copy_from(user_list.rule_based_user_list, rule_based_user_list_info)

    # Issue a mutate request to add the user list, then print the results.
    response = user_list_service.mutate_user_lists(
        customer_id=customer_id, operations=[user_list_operation]
    )
    print(
        "Created combined user list with resource name "
        f"'{response.results[0].resource_name}.'"
    )


def _build_visited_site_rule_info(client, url):
    """Creates a UserListRuleInfo object targeting a visit to a specified URL.

    Args:
        client: An initialized Google Ads client.
        url: The string URL at which the rule will be targeted.
    Returns:
        A populated UserListRuleInfo object.
    """
    user_visited_site_rule = client.get_type("UserListRuleItemInfo")
    # Use a built-in parameter to create a domain URL rule.
    user_visited_site_rule.name = "url__"
    user_visited_site_rule.string_rule_item.operator = (
        client.enums.UserListStringRuleItemOperatorEnum.EQUALS
    )
    user_visited_site_rule.string_rule_item.value = url

    user_visited_site_rule_info = client.get_type("UserListRuleInfo")
    rule_item_group_info = client.get_type("UserListRuleItemGroupInfo")
    rule_item_group_info.rule_items.append(user_visited_site_rule)
    user_visited_site_rule_info.rule_item_groups.append(rule_item_group_info)

    return user_visited_site_rule_info
    # [END add_combined_rule_user_list]


if __name__ == "__main__":
    # GoogleAdsClient will read the google-ads.yaml configuration file in the
    # home directory if none is specified.
    googleads_client = GoogleAdsClient.load_from_storage(version="v11")

    parser = argparse.ArgumentParser(
        description="Creates a combination user list containing users that are "
        "present on any one of the provided user lists."
    )
    # The following argument(s) should be provided to run the example.
    parser.add_argument(
        "-c",
        "--customer_id",
        type=str,
        required=True,
        help="The Google Ads customer ID.",
    )
    args = parser.parse_args()

    try:
        main(googleads_client, args.customer_id)
    except GoogleAdsException as ex:
        print(
            f'Request with ID "{ex.request_id}" failed with status '
            f'"{ex.error.code().name}" and includes the following errors:'
        )
        for error in ex.failure.errors:
            print(f'\tError with message "{error.message}".')
            if error.location:
                for field_path_element in error.location.field_path_elements:
                    print(f"\t\tOn field: {field_path_element.field_name}")
        sys.exit(1)
