__copyright__ = "Copyright (c) 2024-2025 Alex Laird"
__license__ = "MIT"

from typing import Optional


class Selector:
    """
    Can be used to extend the definition of a CSS selector, allowing for programmatic inspection
    of the selections results before determining if selector matches.
    """

    def __init__(self,
                 css_selector: str,
                 text: Optional[str] = None) -> None:
        #: The CSS selector.
        self.css_selector: str = css_selector
        #: The text within the tag that must match.
        self.text: Optional[str] = text


class Selectors:
    """
    A class containing CSS selectors. Extend and override with ``selectors_class`` in the config:

    .. code-block:: python

        from amazonorders.conf import AmazonOrdersConfig

        config = AmazonOrdersConfig(data={"selectors_class": "my_module.MySelectors"})
    """

    ##########################################################################
    # CSS selectors for Pages
    ##########################################################################

    BAD_INDEX_SELECTOR = "html.a-tablet"

    ##########################################################################
    # CSS selectors for AuthForms
    ##########################################################################

    SIGN_IN_FORM_SELECTOR = "form[name='signIn']"
    CLAIM_FORM_SELECTOR = "form[name='signIn'].auth-validate-form"
    INTENT_FORM_SELECTOR = "form#intent-confirmation-form"
    INTENT_MESSAGE_SELECTOR = "div#intent-confirmation-container"
    MFA_DEVICE_SELECT_FORM_SELECTOR = "form#auth-select-device-form"
    MFA_DEVICE_SELECT_INPUT_SELECTOR = "input[name='otpDeviceContext']"
    MFA_DEVICE_SELECT_INPUT_SELECTOR_VALUE = "value"
    MFA_FORM_SELECTOR = "form#auth-mfa-form"
    CAPTCHA_1_FORM_SELECTOR = "form.cvf-widget-form-captcha"
    CAPTCHA_2_FORM_SELECTOR = ["form:has(input[id^='captchacharacters'])", "form[action$='validateCaptcha']"]
    CAPTCHA_OTP_FORM_SELECTOR = "form#verification-code-form"
    DEFAULT_ERROR_TAG_SELECTOR = "div#auth-error-message-box"
    CAPTCHA_1_ERROR_SELECTOR = "div.cvf-widget-alert"
    CAPTCHA_2_ERROR_SELECTOR = "div.a-alert-info"

    ##########################################################################
    # CSS selectors for pagination
    ##########################################################################

    NEXT_PAGE_LINK_SELECTOR = "ul.a-pagination li.a-last a"

    ##########################################################################
    # CSS selectors for Entities and Fields
    #
    # A ``FIELD_`` selector can be either a ``str`` or a ``list``. If a
    # ``list`` is given, each selector in the list will be tried. The
    # ``Parsable`` contains helper functions for parsing fields, including
    # ``simple_parse()``, which is suitable for most fields when a ``FIELD_``
    # is passed.
    ##########################################################################

    ORDER_HISTORY_ENTITY_SELECTOR = ["div.order-card",
                                     "div.order"]
    ORDER_HISTORY_COUNT_SELECTOR = ".js-yo-container span.num-orders"
    ORDER_DETAILS_ENTITY_SELECTOR = ["div#orderDetails",
                                     "div#ordersContainer"]
    ITEM_ENTITY_SELECTOR = ["[data-component='purchasedItems'] .a-fixed-left-grid",
                            "div:has(> div.yohtmlc-item)",
                            ".item-box"]
    SHIPMENT_ENTITY_SELECTOR = ["[data-component='orderCard'] [data-component='shipments'] .a-box",
                                "div.shipment",
                                "div.delivery-box"]
    # Selectors defined here mean we don't have a reliable way to parse all details in an Order, so Items and
    # Shipments will be skipped
    ORDER_SKIP_ITEMS = [
        # Identifies an Amazon Fresh order
        ".brand-info-box .brand-logo img",
        # Identifies a Whole Foods Market order
        "a.yohtmlc-order-details-link[href^='/wholefoodsmarket']",
        # Identifies an order from a physical Amazon store
        Selector("div.yohtmlc-shipment-status-primaryText", "Purchased at Amazon")
    ]
    # Selectors defined here mean the Order will not have parsable totals
    ORDER_SKIP_TOTALS = [
        # Identifies as order that was cancelled
        Selector("div.yohtmlc-shipment-status-primaryText", "Cancelled")
    ]

    #####################################
    # CSS selectors for Item fields
    #####################################

    FIELD_ITEM_IMG_LINK_SELECTOR = "a img"
    FIELD_ITEM_QUANTITY_SELECTOR = [".od-item-view-qty",
                                    "span.item-view-qty",
                                    "span.product-image__qty"]
    FIELD_ITEM_TITLE_SELECTOR = ["[data-component='itemTitle']",
                                 ".yohtmlc-item a", ".yohtmlc-product-title"]
    FIELD_ITEM_LINK_SELECTOR = ["[data-component='itemTitle'] a",
                                ".yohtmlc-item a",
                                "a:has(> .yohtmlc-product-title)",
                                ".yohtmlc-product-title a"]
    FIELD_ITEM_TAG_ITERATOR_SELECTOR = [".yohtmlc-item div"]
    FIELD_ITEM_PRICE_SELECTOR = ["[data-component='unitPrice'] .a-text-price :not(.a-offscreen)",
                                 ".yohtmlc-item .a-color-price"]
    FIELD_ITEM_SELLER_SELECTOR = ["[data-component='orderedMerchant']"] + FIELD_ITEM_TAG_ITERATOR_SELECTOR
    FIELD_ITEM_RETURN_SELECTOR = ["[data-component='itemReturnEligibility']"] + FIELD_ITEM_TAG_ITERATOR_SELECTOR

    #####################################
    # CSS selectors for Order fields
    #####################################

    FIELD_ORDER_DETAILS_LINK_SELECTOR = ["a.yohtmlc-order-details-link",
                                         # Would like to use this or similar, but not yet sure how consistent it is
                                         # ".order-header__header-link-list-item:first-of-type a"
                                         ]
    FIELD_ORDER_NUMBER_SELECTOR = ["[data-component='orderId']",
                                   "[data-component='briefOrderInfo'] div.a-column",
                                   ".order-date-invoice-item :is(bdi, span)[dir='ltr']",
                                   ".yohtmlc-order-id :is(bdi, span)[dir='ltr']",
                                   ":is(bdi, span)[dir='ltr']"]
    FIELD_ORDER_GRAND_TOTAL_SELECTOR = ["div.yohtmlc-order-total span.value",
                                        "div.order-header div.a-column.a-span2",
                                        "div.order-header div.a-col-left .a-span9"]
    FIELD_ORDER_PLACED_DATE_SELECTOR = ["[data-component='orderDate']",
                                        "span.order-date-invoice-item",
                                        "[data-component='briefOrderInfo'] div.a-column",
                                        "div:is(.a-span3, .a-span12)"]
    FIELD_ORDER_PAYMENT_METHOD_SELECTOR = "img.pmts-payment-credit-card-instrument-logo"
    FIELD_ORDER_PAYMENT_METHOD_LAST_4_SELECTOR = "span:has(img.pmts-payment-credit-card-instrument-logo):last-child"
    FIELD_ORDER_SUBTOTALS_TAG_ITERATOR_SELECTOR = ["[data-component='orderSubtotals'] div.a-row",
                                                   "div#od-subtotals div.a-row"]
    FIELD_ORDER_SUBTOTALS_TAG_POPOVER_PRELOAD_SELECTOR = ".a-popover-preload"
    FIELD_ORDER_SUBTOTALS_INNER_TAG_SELECTOR = "div.a-span-last"
    FIELD_ORDER_ADDRESS_SELECTOR = ["div.displayAddressDiv", "[data-component='shippingAddress']"]
    FIELD_ORDER_ADDRESS_FALLBACK_1_SELECTOR = "div.recipient span.a-declarative"
    FIELD_ORDER_ADDRESS_FALLBACK_2_SELECTOR = "script[id^='shipToData']"
    FIELD_ORDER_GIFT_CARD_INSTANCE_SELECTOR = ".gift-card-instance"

    #####################################
    # CSS selectors for Shipment fields
    #####################################

    FIELD_SHIPMENT_TRACKING_LINK_SELECTOR = ["span.track-package-button a",
                                             "a[href*='ship-track?itemId=']"]
    FIELD_SHIPMENT_DELIVERY_STATUS_SELECTOR = ["div.js-shipment-info-container div.a-row",
                                               "span.delivery-box__primary-text",
                                               ".yohtmlc-shipment-status-primaryText",
                                               ".od-status-message"]

    #####################################
    # CSS selectors for Recipient fields
    #####################################

    FIELD_RECIPIENT_NAME_SELECTOR = ["li.displayAddressFullName",
                                     "div:nth-child(1)",
                                     "li:nth-child(1)"]
    FIELD_RECIPIENT_ADDRESS1_SELECTOR = "li.displayAddressAddressLine1"
    FIELD_RECIPIENT_ADDRESS2_SELECTOR = "li.displayAddressAddressLine2"
    FIELD_RECIPIENT_ADDRESS_CITY_STATE_POSTAL_SELECTOR = "li.displayAddressCityStateOrRegionPostalCode"
    FIELD_RECIPIENT_ADDRESS_COUNTRY_SELECTOR = "li.displayAddressCountryName"
    FIELD_RECIPIENT_ADDRESS_FALLBACK_SELECTOR = ["div:nth-child(2)",
                                                 "li:nth-child(2)"]

    #####################################
    # CSS selectors for Seller fields
    #####################################

    FIELD_SELLER_NAME_SELECTOR = ["a", "span"]
    FIELD_SELLER_LINK_SELECTOR = "a"

    #####################################
    # CSS selectors for Transaction fields
    #####################################

    TRANSACTION_HISTORY_FORM_SELECTOR = "form:has(input[name='ppw-widgetState'])"
    TRANSACTION_HISTORY_CONTAINER_SELECTOR = ".pmts-portal-component"
    TRANSACTION_DATE_CONTAINERS_SELECTOR = "div.apx-transaction-date-container"
    TRANSACTIONS_CONTAINER_SELECTOR = "div"
    TRANSACTIONS_SELECTOR = "div.apx-transactions-line-item-component-container:has(*)"

    TRANSACTIONS_NEXT_PAGE_INPUT_SELECTOR = [
        "input[type='submit'][name^='ppw-widgetEvent:DefaultNextPageNavigationEvent']"]
    TRANSACTIONS_NEXT_PAGE_INPUT_STATE_SELECTOR = "input[name='ppw-widgetState']"
    TRANSACTIONS_NEXT_PAGE_INPUT_IE_SELECTOR = "input[name='ie']"

    FIELD_TRANSACTION_COMPLETED_DATE_SELECTOR = "span"
    FIELD_TRANSACTION_PAYMENT_METHOD_SELECTOR = [
        "div.apx-transactions-line-item-component-container > div:nth-child(1) span.a-size-base"]
    FIELD_TRANSACTION_GRAND_TOTAL_SELECTOR = [
        "div.apx-transactions-line-item-component-container > div:nth-child(1) span.a-size-base-plus"]
    FIELD_TRANSACTION_ORDER_NUMBER_SELECTOR = [
        "div.apx-transactions-line-item-component-container div .a-span12"]
    FIELD_TRANSACTION_ORDER_LINK_SELECTOR = [
        "div.apx-transactions-line-item-component-container a.a-link-normal"]
    FIELD_TRANSACTION_SELLER_NAME_SELECTOR = [
        "div.apx-transactions-line-item-component-container :has(a.a-link-normal) + div"]
