# coding=utf-8
# *** WARNING: this file was generated by pulumi-language-python. ***
# *** Do not edit by hand unless you're certain you know what you are doing! ***

import builtins as _builtins
import warnings
import sys
import pulumi
import pulumi.runtime
from typing import Any, Mapping, Optional, Sequence, Union, overload
if sys.version_info >= (3, 11):
    from typing import NotRequired, TypedDict, TypeAlias
else:
    from typing_extensions import NotRequired, TypedDict, TypeAlias
from .. import _utilities
from . import outputs
from ._inputs import *

__all__ = ['SignonPolicyRulesArgs', 'SignonPolicyRules']

@pulumi.input_type
class SignonPolicyRulesArgs:
    def __init__(__self__, *,
                 policy_id: pulumi.Input[_builtins.str],
                 rules: Optional[pulumi.Input[Sequence[pulumi.Input['SignonPolicyRulesRuleArgs']]]] = None):
        """
        The set of arguments for constructing a SignonPolicyRules resource.

        :param pulumi.Input[_builtins.str] policy_id: ID of the policy to manage rules for.
        :param pulumi.Input[Sequence[pulumi.Input['SignonPolicyRulesRuleArgs']]] rules: List of policy rules. Rules are processed in priority order (lowest number = highest priority).
        """
        pulumi.set(__self__, "policy_id", policy_id)
        if rules is not None:
            pulumi.set(__self__, "rules", rules)

    @_builtins.property
    @pulumi.getter(name="policyId")
    def policy_id(self) -> pulumi.Input[_builtins.str]:
        """
        ID of the policy to manage rules for.
        """
        return pulumi.get(self, "policy_id")

    @policy_id.setter
    def policy_id(self, value: pulumi.Input[_builtins.str]):
        pulumi.set(self, "policy_id", value)

    @_builtins.property
    @pulumi.getter
    def rules(self) -> Optional[pulumi.Input[Sequence[pulumi.Input['SignonPolicyRulesRuleArgs']]]]:
        """
        List of policy rules. Rules are processed in priority order (lowest number = highest priority).
        """
        return pulumi.get(self, "rules")

    @rules.setter
    def rules(self, value: Optional[pulumi.Input[Sequence[pulumi.Input['SignonPolicyRulesRuleArgs']]]]):
        pulumi.set(self, "rules", value)


@pulumi.input_type
class _SignonPolicyRulesState:
    def __init__(__self__, *,
                 policy_id: Optional[pulumi.Input[_builtins.str]] = None,
                 rules: Optional[pulumi.Input[Sequence[pulumi.Input['SignonPolicyRulesRuleArgs']]]] = None):
        """
        Input properties used for looking up and filtering SignonPolicyRules resources.

        :param pulumi.Input[_builtins.str] policy_id: ID of the policy to manage rules for.
        :param pulumi.Input[Sequence[pulumi.Input['SignonPolicyRulesRuleArgs']]] rules: List of policy rules. Rules are processed in priority order (lowest number = highest priority).
        """
        if policy_id is not None:
            pulumi.set(__self__, "policy_id", policy_id)
        if rules is not None:
            pulumi.set(__self__, "rules", rules)

    @_builtins.property
    @pulumi.getter(name="policyId")
    def policy_id(self) -> Optional[pulumi.Input[_builtins.str]]:
        """
        ID of the policy to manage rules for.
        """
        return pulumi.get(self, "policy_id")

    @policy_id.setter
    def policy_id(self, value: Optional[pulumi.Input[_builtins.str]]):
        pulumi.set(self, "policy_id", value)

    @_builtins.property
    @pulumi.getter
    def rules(self) -> Optional[pulumi.Input[Sequence[pulumi.Input['SignonPolicyRulesRuleArgs']]]]:
        """
        List of policy rules. Rules are processed in priority order (lowest number = highest priority).
        """
        return pulumi.get(self, "rules")

    @rules.setter
    def rules(self, value: Optional[pulumi.Input[Sequence[pulumi.Input['SignonPolicyRulesRuleArgs']]]]):
        pulumi.set(self, "rules", value)


@pulumi.type_token("okta:app/signonPolicyRules:SignonPolicyRules")
class SignonPolicyRules(pulumi.CustomResource):
    @overload
    def __init__(__self__,
                 resource_name: str,
                 opts: Optional[pulumi.ResourceOptions] = None,
                 policy_id: Optional[pulumi.Input[_builtins.str]] = None,
                 rules: Optional[pulumi.Input[Sequence[pulumi.Input[Union['SignonPolicyRulesRuleArgs', 'SignonPolicyRulesRuleArgsDict']]]]] = None,
                 __props__=None):
        """
        ## # app.SignonPolicyRules

        Manages multiple app sign-on policy rules for a single policy. This resource allows you to define all rules for a policy in a single configuration block, ensuring consistent priority ordering and avoiding drift issues.

        > **IMPORTANT:** This resource uses name-first matching to identify and update rules. When migrating from individual `AppSignonPolicyRule` resources, ensure rule names remain consistent to enable safe adoption without data loss.

        ## Example Usage

        ```python
        import pulumi
        import pulumi_okta as okta

        example = okta.app.SignonPolicyRules("example",
            policy_id=example_okta_app_signon_policy["id"],
            rules=[
                {
                    "name": "High Priority Rule",
                    "priority": 1,
                    "factor_mode": "2FA",
                    "re_authentication_frequency": "PT2H",
                    "status": "ACTIVE",
                },
                {
                    "name": "Low Priority Rule",
                    "priority": 2,
                    "factor_mode": "1FA",
                    "access": "ALLOW",
                    "status": "ACTIVE",
                },
                {
                    "name": "Deny Rule",
                    "priority": 3,
                    "access": "DENY",
                    "status": "ACTIVE",
                },
            ])
        ```

        ## Priority Management

        > **IMPORTANT:** When managing priorities, follow Okta's top-down synchronization strategy to avoid automatic priority shifting. Always update rules in priority order (P1 → PN) to prevent cascading shifts.

        ### Priority Behavior

        - Priorities are **0-indexed** but can be any positive integer.
        - When you omit `priority` in config, Terraform will display the actual priority assigned by Okta in the state.
        - Okta allows gaps in priorities (e.g., priorities 1, 2, 5, 99 are valid).
        - **Maximum of 99 rules per policy:** You can define up to 99 custom rules. Priority 99 is reserved for the system Catch-all Rule.
        - If you update multiple rules simultaneously and priorities conflict, Okta may automatically shift priorities to resolve conflicts. To prevent this:
          1. Use explicit, sequential priority values (1, 2, 3, 4, 5).
          2. Avoid updating rules with the same priority.
          3. Consider using temporary high priorities (100+) if reordering is needed.

        ### System Rules and Catch-all Rule

        - **Catch-all Rule:** Every policy includes a system-level Catch-all Rule with priority 99. This is the default rule that applies if no other rules match.
        - **Immutable:** System rules (like "Catch-all Rule") cannot be modified, deleted, or have their conditions/priorities changed.
        - **Import behavior:** If you import a policy with a Catch-all Rule, it will appear in your state but cannot be managed by Terraform. Omit it from your configuration.

        ## Migration from AppSignonPolicyRule

        If you currently use multiple individual `AppSignonPolicyRule` resources, follow these steps to safely migrate to the grouped resource:

        ### Step 1: Backup Your State

        ### Step 2: Identify Rule IDs and Names

        List all rules in your policy to identify their IDs and names:

        ### Step 4: Create the Grouped Resource Configuration

        Create a new `app.SignonPolicyRules` resource with the same rules. Use **rule names as the matching key** (do NOT include `id` unless adopting an existing rule):

        ```python
        import pulumi
        import pulumi_okta as okta

        migrated = okta.app.SignonPolicyRules("migrated",
            policy_id=my_policy["id"],
            rules=[
                {
                    "name": "High Priority Rule",
                    "priority": 1,
                    "factor_mode": "2FA",
                    "re_authentication_frequency": "PT2H",
                    "status": "ACTIVE",
                },
                {
                    "name": "Second Rule",
                    "priority": 2,
                    "factor_mode": "1FA",
                    "status": "ACTIVE",
                },
                {
                    "name": "Deny Rule",
                    "priority": 3,
                    "access": "DENY",
                    "status": "ACTIVE",
                },
            ])
        ```

        ### Step 5: Plan and Verify

        Run `pulumi preview` to see if any changes will be made:

        **Expected outcome:** Either "No changes" or only legitimate config updates. If the plan shows unexpected deletes or recreates:
        - Verify rule names match exactly (case-sensitive).
        - Check that attributes (access, factor_mode, etc.) match Okta's current state.
        - Ensure you're not declaring system rules (e.g., Catch-all Rule).

        ### Step 6: Apply the Migration

        ### Step 6: Verify Final State

        ## Important Migration Notes

        ### Priority Differences

        When migrating from `AppSignonPolicyRule` (single-rule resource) to `app.SignonPolicyRules` (grouped resource):

        - **Old behavior:** Single-rule resource defaults to `priority = 0` in Terraform state, even if Okta assigned a different priority.
        - **New behavior:** Grouped resource reflects the actual priority assigned by Okta. When you omit `priority`, the state will show the real Okta-assigned priority.

        **Action:** Explicitly set `priority` values in your configuration to avoid unexpected changes during migration.

        ### Name-First Matching

        The grouped resource matches rules by **name first**, not by ID:

        - If you rename a rule in config, the provider will match it to the existing rule by the new name.
        - If a name doesn't exist in Okta, a new rule is created.
        - This design prevents accidental re-matching when state order differs from config order.

        ### System Rules

        System rules (e.g., "Catch-all Rule") cannot be managed:

        - If your policy has a system rule, do NOT declare it in your configuration.
        - The provider will detect it during import/read but will not attempt to modify or delete it.
        - System rules are read-only from Terraform's perspective.

        ## Troubleshooting

        ### Plan shows "1 to change" but config matches Okta

        **Cause:** State and config rule order differ, triggering re-matching.

        **Solution:** Verify rule names match exactly (case-sensitive) and attributes are correct. Run `pulumi preview -refresh=true` to refresh state from Okta.

        ### Priorities shift unexpectedly after apply

        **Cause:** Okta automatically shifts priorities when updates conflict. This is expected behavior per Okta's prioritization rules.

        **Solution:** Use explicit, sequential priorities (1, 2, 3, ...) instead of 0-indexed or sparse values. Avoid updating multiple rules simultaneously with overlapping priorities.

        ### Error: "System rule cannot be modified"

        **Cause:** You attempted to set conditions on a system rule (Catch-all Rule).

        **Solution:** Remove the system rule from your configuration. System rules are immutable.

        ## See Also

        - AppSignonPolicy - Create and manage app sign-on policies.
        - [Okta Policy Rule Prioritization Guide](https://developer.okta.com/docs/guides/policy-rule-prioritization/main/) - Learn about priority management and top-down synchronization.

        ## Import

        Import an existing policy's rules:

        ```sh
        $ pulumi import okta:app/signonPolicyRules:SignonPolicyRules example <policy_id>
        ```

        This will populate your state with all rules for the policy (including system rules). Update your configuration to match.


        :param str resource_name: The name of the resource.
        :param pulumi.ResourceOptions opts: Options for the resource.
        :param pulumi.Input[_builtins.str] policy_id: ID of the policy to manage rules for.
        :param pulumi.Input[Sequence[pulumi.Input[Union['SignonPolicyRulesRuleArgs', 'SignonPolicyRulesRuleArgsDict']]]] rules: List of policy rules. Rules are processed in priority order (lowest number = highest priority).
        """
        ...
    @overload
    def __init__(__self__,
                 resource_name: str,
                 args: SignonPolicyRulesArgs,
                 opts: Optional[pulumi.ResourceOptions] = None):
        """
        ## # app.SignonPolicyRules

        Manages multiple app sign-on policy rules for a single policy. This resource allows you to define all rules for a policy in a single configuration block, ensuring consistent priority ordering and avoiding drift issues.

        > **IMPORTANT:** This resource uses name-first matching to identify and update rules. When migrating from individual `AppSignonPolicyRule` resources, ensure rule names remain consistent to enable safe adoption without data loss.

        ## Example Usage

        ```python
        import pulumi
        import pulumi_okta as okta

        example = okta.app.SignonPolicyRules("example",
            policy_id=example_okta_app_signon_policy["id"],
            rules=[
                {
                    "name": "High Priority Rule",
                    "priority": 1,
                    "factor_mode": "2FA",
                    "re_authentication_frequency": "PT2H",
                    "status": "ACTIVE",
                },
                {
                    "name": "Low Priority Rule",
                    "priority": 2,
                    "factor_mode": "1FA",
                    "access": "ALLOW",
                    "status": "ACTIVE",
                },
                {
                    "name": "Deny Rule",
                    "priority": 3,
                    "access": "DENY",
                    "status": "ACTIVE",
                },
            ])
        ```

        ## Priority Management

        > **IMPORTANT:** When managing priorities, follow Okta's top-down synchronization strategy to avoid automatic priority shifting. Always update rules in priority order (P1 → PN) to prevent cascading shifts.

        ### Priority Behavior

        - Priorities are **0-indexed** but can be any positive integer.
        - When you omit `priority` in config, Terraform will display the actual priority assigned by Okta in the state.
        - Okta allows gaps in priorities (e.g., priorities 1, 2, 5, 99 are valid).
        - **Maximum of 99 rules per policy:** You can define up to 99 custom rules. Priority 99 is reserved for the system Catch-all Rule.
        - If you update multiple rules simultaneously and priorities conflict, Okta may automatically shift priorities to resolve conflicts. To prevent this:
          1. Use explicit, sequential priority values (1, 2, 3, 4, 5).
          2. Avoid updating rules with the same priority.
          3. Consider using temporary high priorities (100+) if reordering is needed.

        ### System Rules and Catch-all Rule

        - **Catch-all Rule:** Every policy includes a system-level Catch-all Rule with priority 99. This is the default rule that applies if no other rules match.
        - **Immutable:** System rules (like "Catch-all Rule") cannot be modified, deleted, or have their conditions/priorities changed.
        - **Import behavior:** If you import a policy with a Catch-all Rule, it will appear in your state but cannot be managed by Terraform. Omit it from your configuration.

        ## Migration from AppSignonPolicyRule

        If you currently use multiple individual `AppSignonPolicyRule` resources, follow these steps to safely migrate to the grouped resource:

        ### Step 1: Backup Your State

        ### Step 2: Identify Rule IDs and Names

        List all rules in your policy to identify their IDs and names:

        ### Step 4: Create the Grouped Resource Configuration

        Create a new `app.SignonPolicyRules` resource with the same rules. Use **rule names as the matching key** (do NOT include `id` unless adopting an existing rule):

        ```python
        import pulumi
        import pulumi_okta as okta

        migrated = okta.app.SignonPolicyRules("migrated",
            policy_id=my_policy["id"],
            rules=[
                {
                    "name": "High Priority Rule",
                    "priority": 1,
                    "factor_mode": "2FA",
                    "re_authentication_frequency": "PT2H",
                    "status": "ACTIVE",
                },
                {
                    "name": "Second Rule",
                    "priority": 2,
                    "factor_mode": "1FA",
                    "status": "ACTIVE",
                },
                {
                    "name": "Deny Rule",
                    "priority": 3,
                    "access": "DENY",
                    "status": "ACTIVE",
                },
            ])
        ```

        ### Step 5: Plan and Verify

        Run `pulumi preview` to see if any changes will be made:

        **Expected outcome:** Either "No changes" or only legitimate config updates. If the plan shows unexpected deletes or recreates:
        - Verify rule names match exactly (case-sensitive).
        - Check that attributes (access, factor_mode, etc.) match Okta's current state.
        - Ensure you're not declaring system rules (e.g., Catch-all Rule).

        ### Step 6: Apply the Migration

        ### Step 6: Verify Final State

        ## Important Migration Notes

        ### Priority Differences

        When migrating from `AppSignonPolicyRule` (single-rule resource) to `app.SignonPolicyRules` (grouped resource):

        - **Old behavior:** Single-rule resource defaults to `priority = 0` in Terraform state, even if Okta assigned a different priority.
        - **New behavior:** Grouped resource reflects the actual priority assigned by Okta. When you omit `priority`, the state will show the real Okta-assigned priority.

        **Action:** Explicitly set `priority` values in your configuration to avoid unexpected changes during migration.

        ### Name-First Matching

        The grouped resource matches rules by **name first**, not by ID:

        - If you rename a rule in config, the provider will match it to the existing rule by the new name.
        - If a name doesn't exist in Okta, a new rule is created.
        - This design prevents accidental re-matching when state order differs from config order.

        ### System Rules

        System rules (e.g., "Catch-all Rule") cannot be managed:

        - If your policy has a system rule, do NOT declare it in your configuration.
        - The provider will detect it during import/read but will not attempt to modify or delete it.
        - System rules are read-only from Terraform's perspective.

        ## Troubleshooting

        ### Plan shows "1 to change" but config matches Okta

        **Cause:** State and config rule order differ, triggering re-matching.

        **Solution:** Verify rule names match exactly (case-sensitive) and attributes are correct. Run `pulumi preview -refresh=true` to refresh state from Okta.

        ### Priorities shift unexpectedly after apply

        **Cause:** Okta automatically shifts priorities when updates conflict. This is expected behavior per Okta's prioritization rules.

        **Solution:** Use explicit, sequential priorities (1, 2, 3, ...) instead of 0-indexed or sparse values. Avoid updating multiple rules simultaneously with overlapping priorities.

        ### Error: "System rule cannot be modified"

        **Cause:** You attempted to set conditions on a system rule (Catch-all Rule).

        **Solution:** Remove the system rule from your configuration. System rules are immutable.

        ## See Also

        - AppSignonPolicy - Create and manage app sign-on policies.
        - [Okta Policy Rule Prioritization Guide](https://developer.okta.com/docs/guides/policy-rule-prioritization/main/) - Learn about priority management and top-down synchronization.

        ## Import

        Import an existing policy's rules:

        ```sh
        $ pulumi import okta:app/signonPolicyRules:SignonPolicyRules example <policy_id>
        ```

        This will populate your state with all rules for the policy (including system rules). Update your configuration to match.


        :param str resource_name: The name of the resource.
        :param SignonPolicyRulesArgs args: The arguments to use to populate this resource's properties.
        :param pulumi.ResourceOptions opts: Options for the resource.
        """
        ...
    def __init__(__self__, resource_name: str, *args, **kwargs):
        resource_args, opts = _utilities.get_resource_args_opts(SignonPolicyRulesArgs, pulumi.ResourceOptions, *args, **kwargs)
        if resource_args is not None:
            __self__._internal_init(resource_name, opts, **resource_args.__dict__)
        else:
            __self__._internal_init(resource_name, *args, **kwargs)

    def _internal_init(__self__,
                 resource_name: str,
                 opts: Optional[pulumi.ResourceOptions] = None,
                 policy_id: Optional[pulumi.Input[_builtins.str]] = None,
                 rules: Optional[pulumi.Input[Sequence[pulumi.Input[Union['SignonPolicyRulesRuleArgs', 'SignonPolicyRulesRuleArgsDict']]]]] = None,
                 __props__=None):
        opts = pulumi.ResourceOptions.merge(_utilities.get_resource_opts_defaults(), opts)
        if not isinstance(opts, pulumi.ResourceOptions):
            raise TypeError('Expected resource options to be a ResourceOptions instance')
        if opts.id is None:
            if __props__ is not None:
                raise TypeError('__props__ is only valid when passed in combination with a valid opts.id to get an existing resource')
            __props__ = SignonPolicyRulesArgs.__new__(SignonPolicyRulesArgs)

            if policy_id is None and not opts.urn:
                raise TypeError("Missing required property 'policy_id'")
            __props__.__dict__["policy_id"] = policy_id
            __props__.__dict__["rules"] = rules
        super(SignonPolicyRules, __self__).__init__(
            'okta:app/signonPolicyRules:SignonPolicyRules',
            resource_name,
            __props__,
            opts)

    @staticmethod
    def get(resource_name: str,
            id: pulumi.Input[str],
            opts: Optional[pulumi.ResourceOptions] = None,
            policy_id: Optional[pulumi.Input[_builtins.str]] = None,
            rules: Optional[pulumi.Input[Sequence[pulumi.Input[Union['SignonPolicyRulesRuleArgs', 'SignonPolicyRulesRuleArgsDict']]]]] = None) -> 'SignonPolicyRules':
        """
        Get an existing SignonPolicyRules resource's state with the given name, id, and optional extra
        properties used to qualify the lookup.

        :param str resource_name: The unique name of the resulting resource.
        :param pulumi.Input[str] id: The unique provider ID of the resource to lookup.
        :param pulumi.ResourceOptions opts: Options for the resource.
        :param pulumi.Input[_builtins.str] policy_id: ID of the policy to manage rules for.
        :param pulumi.Input[Sequence[pulumi.Input[Union['SignonPolicyRulesRuleArgs', 'SignonPolicyRulesRuleArgsDict']]]] rules: List of policy rules. Rules are processed in priority order (lowest number = highest priority).
        """
        opts = pulumi.ResourceOptions.merge(opts, pulumi.ResourceOptions(id=id))

        __props__ = _SignonPolicyRulesState.__new__(_SignonPolicyRulesState)

        __props__.__dict__["policy_id"] = policy_id
        __props__.__dict__["rules"] = rules
        return SignonPolicyRules(resource_name, opts=opts, __props__=__props__)

    @_builtins.property
    @pulumi.getter(name="policyId")
    def policy_id(self) -> pulumi.Output[_builtins.str]:
        """
        ID of the policy to manage rules for.
        """
        return pulumi.get(self, "policy_id")

    @_builtins.property
    @pulumi.getter
    def rules(self) -> pulumi.Output[Optional[Sequence['outputs.SignonPolicyRulesRule']]]:
        """
        List of policy rules. Rules are processed in priority order (lowest number = highest priority).
        """
        return pulumi.get(self, "rules")

