# !!!
# WARNING: This file is autogenerated
# Only modify code within MANUAL() sections
# or your changes may be overwritten later!
# !!!

from __future__ import annotations

from typing import Any, Dict, Optional, Union

from stytch.consumer.models.fraud import RuleAction
from stytch.consumer.models.fraud_rules import ListResponse, SetResponse
from stytch.core.api_base import ApiBase
from stytch.core.http.client import AsyncClient, SyncClient


class Rules:
    def __init__(
        self, api_base: ApiBase, sync_client: SyncClient, async_client: AsyncClient
    ) -> None:
        self.api_base = api_base
        self.sync_client = sync_client
        self.async_client = async_client

    def set(
        self,
        action: Union[RuleAction, str],
        visitor_id: Optional[str] = None,
        browser_id: Optional[str] = None,
        visitor_fingerprint: Optional[str] = None,
        browser_fingerprint: Optional[str] = None,
        hardware_fingerprint: Optional[str] = None,
        network_fingerprint: Optional[str] = None,
        expires_in_minutes: Optional[int] = None,
        description: Optional[str] = None,
        cidr_block: Optional[str] = None,
        country_code: Optional[str] = None,
        asn: Optional[str] = None,
    ) -> SetResponse:
        """Set a rule for a particular `visitor_id`, `browser_id`, `visitor_fingerprint`, `browser_fingerprint`, `hardware_fingerprint`, `network_fingerprint`, `cidr_block`, `asn`, or `country_code`. This is helpful in cases where you want to allow or block a specific user or fingerprint. You should be careful when setting rules for `browser_fingerprint`, `hardware_fingerprint`, or `network_fingerprint` as they can be shared across multiple users, and you could affect more users than intended.

        You may not set an `ALLOW` rule for a `country_code`.

        Rules are applied in the order specified above. For example, if an end user has an `ALLOW` rule set for their `visitor_id` but a `BLOCK` rule set for their `hardware_fingerprint`, they will receive an `ALLOW` verdict because the `visitor_id` rule takes precedence.

        If there are conflicts between multiple `cidr_block` rules (for example, if the `ip_address` of the end user overlaps with multiple CIDR blocks that have rules set), the conflicts are resolved as follows:
        - The smallest block size takes precedence. For example, if an `ip_address` overlaps with a `cidr_block` rule of `ALLOW` for a block with a prefix of `/32` and a `cidr_block` rule of `BLOCK` with a prefix of `/24`, the rule match verdict will be `ALLOW`.
        - Among equivalent size blocks, `BLOCK` takes precedence over `CHALLENGE`, which takes precedence over `ALLOW`. For example, if an `ip_address` overlaps with two `cidr_block` rules with blocks of the same size that return `CHALLENGE` and `ALLOW`, the rule match verdict will be `CHALLENGE`.

        Fields:
          - action: The action that should be returned by a fingerprint lookup for that identifier with a `RULE_MATCH` reason. The following values are valid: `ALLOW`, `BLOCK`, `CHALLENGE`, or `NONE`. For country codes, `ALLOW` actions are not allowed. If a `NONE` action is specified, it will clear the stored rule.
          - visitor_id: The visitor ID we want to set a rule for. Only one identifier can be specified in the request.
          - browser_id: The browser ID we want to set a rule for. Only one identifier can be specified in the request.
          - visitor_fingerprint: The visitor fingerprint we want to set a rule for. Only one identifier can be specified in the request.
          - browser_fingerprint: The browser fingerprint we want to set a rule for. Only one identifier can be specified in the request.
          - hardware_fingerprint: The hardware fingerprint we want to set a rule for. Only one identifier can be specified in the request.
          - network_fingerprint: The network fingerprint we want to set a rule for. Only one identifier can be specified in the request.
          - expires_in_minutes: The number of minutes until this rule expires. If no `expires_in_minutes` is specified, then the rule is kept permanently.
          - description: An optional description for the rule.
          - cidr_block: The CIDR block we want to set a rule for. You may pass either an IP address or a CIDR block. The CIDR block prefix must be between 16 and 32, inclusive. If an end user's IP address is within this CIDR block, this rule will be applied. Only one identifier can be specified in the request.
          - country_code: The country code we want to set a rule for. The country code must be a valid ISO 3166-1 alpha-2 code. You may not set `ALLOW` rules for country codes. Only one identifier can be specified in the request.
          - asn: The ASN we want to set a rule for. The ASN must be the string representation of an integer between 0 and 4294967295, inclusive. Only one identifier can be specified in the request.
        """  # noqa
        headers: Dict[str, str] = {}
        data: Dict[str, Any] = {
            "action": action,
        }
        if visitor_id is not None:
            data["visitor_id"] = visitor_id
        if browser_id is not None:
            data["browser_id"] = browser_id
        if visitor_fingerprint is not None:
            data["visitor_fingerprint"] = visitor_fingerprint
        if browser_fingerprint is not None:
            data["browser_fingerprint"] = browser_fingerprint
        if hardware_fingerprint is not None:
            data["hardware_fingerprint"] = hardware_fingerprint
        if network_fingerprint is not None:
            data["network_fingerprint"] = network_fingerprint
        if expires_in_minutes is not None:
            data["expires_in_minutes"] = expires_in_minutes
        if description is not None:
            data["description"] = description
        if cidr_block is not None:
            data["cidr_block"] = cidr_block
        if country_code is not None:
            data["country_code"] = country_code
        if asn is not None:
            data["asn"] = asn

        url = self.api_base.url_for("/v1/rules/set", data)
        res = self.sync_client.post(url, data, headers)
        return SetResponse.from_json(res.response.status_code, res.json)

    async def set_async(
        self,
        action: RuleAction,
        visitor_id: Optional[str] = None,
        browser_id: Optional[str] = None,
        visitor_fingerprint: Optional[str] = None,
        browser_fingerprint: Optional[str] = None,
        hardware_fingerprint: Optional[str] = None,
        network_fingerprint: Optional[str] = None,
        expires_in_minutes: Optional[int] = None,
        description: Optional[str] = None,
        cidr_block: Optional[str] = None,
        country_code: Optional[str] = None,
        asn: Optional[str] = None,
    ) -> SetResponse:
        """Set a rule for a particular `visitor_id`, `browser_id`, `visitor_fingerprint`, `browser_fingerprint`, `hardware_fingerprint`, `network_fingerprint`, `cidr_block`, `asn`, or `country_code`. This is helpful in cases where you want to allow or block a specific user or fingerprint. You should be careful when setting rules for `browser_fingerprint`, `hardware_fingerprint`, or `network_fingerprint` as they can be shared across multiple users, and you could affect more users than intended.

        You may not set an `ALLOW` rule for a `country_code`.

        Rules are applied in the order specified above. For example, if an end user has an `ALLOW` rule set for their `visitor_id` but a `BLOCK` rule set for their `hardware_fingerprint`, they will receive an `ALLOW` verdict because the `visitor_id` rule takes precedence.

        If there are conflicts between multiple `cidr_block` rules (for example, if the `ip_address` of the end user overlaps with multiple CIDR blocks that have rules set), the conflicts are resolved as follows:
        - The smallest block size takes precedence. For example, if an `ip_address` overlaps with a `cidr_block` rule of `ALLOW` for a block with a prefix of `/32` and a `cidr_block` rule of `BLOCK` with a prefix of `/24`, the rule match verdict will be `ALLOW`.
        - Among equivalent size blocks, `BLOCK` takes precedence over `CHALLENGE`, which takes precedence over `ALLOW`. For example, if an `ip_address` overlaps with two `cidr_block` rules with blocks of the same size that return `CHALLENGE` and `ALLOW`, the rule match verdict will be `CHALLENGE`.

        Fields:
          - action: The action that should be returned by a fingerprint lookup for that identifier with a `RULE_MATCH` reason. The following values are valid: `ALLOW`, `BLOCK`, `CHALLENGE`, or `NONE`. For country codes, `ALLOW` actions are not allowed. If a `NONE` action is specified, it will clear the stored rule.
          - visitor_id: The visitor ID we want to set a rule for. Only one identifier can be specified in the request.
          - browser_id: The browser ID we want to set a rule for. Only one identifier can be specified in the request.
          - visitor_fingerprint: The visitor fingerprint we want to set a rule for. Only one identifier can be specified in the request.
          - browser_fingerprint: The browser fingerprint we want to set a rule for. Only one identifier can be specified in the request.
          - hardware_fingerprint: The hardware fingerprint we want to set a rule for. Only one identifier can be specified in the request.
          - network_fingerprint: The network fingerprint we want to set a rule for. Only one identifier can be specified in the request.
          - expires_in_minutes: The number of minutes until this rule expires. If no `expires_in_minutes` is specified, then the rule is kept permanently.
          - description: An optional description for the rule.
          - cidr_block: The CIDR block we want to set a rule for. You may pass either an IP address or a CIDR block. The CIDR block prefix must be between 16 and 32, inclusive. If an end user's IP address is within this CIDR block, this rule will be applied. Only one identifier can be specified in the request.
          - country_code: The country code we want to set a rule for. The country code must be a valid ISO 3166-1 alpha-2 code. You may not set `ALLOW` rules for country codes. Only one identifier can be specified in the request.
          - asn: The ASN we want to set a rule for. The ASN must be the string representation of an integer between 0 and 4294967295, inclusive. Only one identifier can be specified in the request.
        """  # noqa
        headers: Dict[str, str] = {}
        data: Dict[str, Any] = {
            "action": action,
        }
        if visitor_id is not None:
            data["visitor_id"] = visitor_id
        if browser_id is not None:
            data["browser_id"] = browser_id
        if visitor_fingerprint is not None:
            data["visitor_fingerprint"] = visitor_fingerprint
        if browser_fingerprint is not None:
            data["browser_fingerprint"] = browser_fingerprint
        if hardware_fingerprint is not None:
            data["hardware_fingerprint"] = hardware_fingerprint
        if network_fingerprint is not None:
            data["network_fingerprint"] = network_fingerprint
        if expires_in_minutes is not None:
            data["expires_in_minutes"] = expires_in_minutes
        if description is not None:
            data["description"] = description
        if cidr_block is not None:
            data["cidr_block"] = cidr_block
        if country_code is not None:
            data["country_code"] = country_code
        if asn is not None:
            data["asn"] = asn

        url = self.api_base.url_for("/v1/rules/set", data)
        res = await self.async_client.post(url, data, headers)
        return SetResponse.from_json(res.response.status, res.json)

    def list(
        self,
        cursor: Optional[str] = None,
        limit: Optional[int] = None,
    ) -> ListResponse:
        """Get all rules that have been set for your project.

        Fields:
          - cursor: The `cursor` field allows you to paginate through your results. Each result array is limited to 100 results. If your query returns more than 100 results, you will need to paginate the responses using the `cursor`. If you receive a response that includes a non-null `next_cursor`, repeat the request with the `next_cursor` value set to the `cursor` field to retrieve the next page of results. Continue to make requests until the `next_cursor` in the response is null.
          - limit: The number of results to return per page. The default limit is 10. A maximum of 100 results can be returned by a single get request. If the total size of your result set is greater than one page size, you must paginate the response. See the `cursor` field.
        """  # noqa
        headers: Dict[str, str] = {}
        data: Dict[str, Any] = {}
        if cursor is not None:
            data["cursor"] = cursor
        if limit is not None:
            data["limit"] = limit

        url = self.api_base.url_for("/v1/rules/list", data)
        res = self.sync_client.post(url, data, headers)
        return ListResponse.from_json(res.response.status_code, res.json)

    async def list_async(
        self,
        cursor: Optional[str] = None,
        limit: Optional[int] = None,
    ) -> ListResponse:
        """Get all rules that have been set for your project.

        Fields:
          - cursor: The `cursor` field allows you to paginate through your results. Each result array is limited to 100 results. If your query returns more than 100 results, you will need to paginate the responses using the `cursor`. If you receive a response that includes a non-null `next_cursor`, repeat the request with the `next_cursor` value set to the `cursor` field to retrieve the next page of results. Continue to make requests until the `next_cursor` in the response is null.
          - limit: The number of results to return per page. The default limit is 10. A maximum of 100 results can be returned by a single get request. If the total size of your result set is greater than one page size, you must paginate the response. See the `cursor` field.
        """  # noqa
        headers: Dict[str, str] = {}
        data: Dict[str, Any] = {}
        if cursor is not None:
            data["cursor"] = cursor
        if limit is not None:
            data["limit"] = limit

        url = self.api_base.url_for("/v1/rules/list", data)
        res = await self.async_client.post(url, data, headers)
        return ListResponse.from_json(res.response.status, res.json)
