// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

import { APIResource } from '../../../../core/resource';
import {
  CursorPaginationAfter,
  type CursorPaginationAfterParams,
  PagePromise,
} from '../../../../core/pagination';
import { RequestOptions } from '../../../../internal/request-options';
import { path } from '../../../../internal/utils/path';

export class BaseChangelog extends APIResource {
  static override readonly _key: readonly ['flagship', 'apps', 'flags', 'changelog'] = Object.freeze([
    'flagship',
    'apps',
    'flags',
    'changelog',
  ] as const);

  /**
   * Returns the audit history for a flag, newest first. Each entry includes the
   * event type and full flag state after the change; `update` entries include a
   * field-level diff. Capped at 200 entries per flag.
   */
  list(
    flagKey: string,
    params: ChangelogListParams,
    options?: RequestOptions,
  ): PagePromise<ChangelogListResponsesCursorPaginationAfter, ChangelogListResponse> {
    const { account_id, app_id, ...query } = params;
    return this._client.getAPIList(
      path`/accounts/${account_id}/flagship/apps/${app_id}/flags/${flagKey}/changelog`,
      CursorPaginationAfter<ChangelogListResponse>,
      { query, ...options },
    );
  }
}
export class Changelog extends BaseChangelog {}

export type ChangelogListResponsesCursorPaginationAfter = CursorPaginationAfter<ChangelogListResponse>;

export type ChangelogListResponse =
  | ChangelogListResponse.UnionMember0
  | ChangelogListResponse.UnionMember1
  | ChangelogListResponse.UnionMember2;

export namespace ChangelogListResponse {
  export interface UnionMember0 {
    after: UnionMember0.After;

    event: 'create';

    flag_key: string;
  }

  export namespace UnionMember0 {
    export interface After {
      /**
       * Variation the API serves when the flag is off, or when it's on but no rule
       * matches the context. Must be a key in `variations`.
       */
      default_variation: string;

      /**
       * When false, the flag bypasses all rules and always serves `default_variation`.
       */
      enabled: boolean;

      /**
       * Unique identifier for the flag within an app. Used in all evaluation and SDK
       * calls.
       */
      key: string;

      /**
       * Targeting rules evaluated in ascending `priority`; the first matching rule wins.
       * An empty array means the flag always serves `default_variation`.
       */
      rules: Array<After.Rule>;

      /**
       * Server-inferred value type shared by all of the flag's variations.
       */
      type: 'boolean' | 'string' | 'number' | 'json';

      /**
       * Map of variation name to value. All values share the same type (boolean, string,
       * number, or JSON object/array), and each serialized value stays within 10KB.
       */
      variations: {
        [key: string]: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
      };

      /**
       * Optional operator-facing description. It does not affect flag evaluation.
       */
      description?: string | null;

      updated_at?: string;

      updated_by?: string;
    }

    export namespace After {
      export interface Rule {
        /**
         * Conditions the context must satisfy for this rule to match. An empty array
         * matches all contexts.
         */
        conditions: Array<Rule.UnionMember0 | Rule.UnionMember1>;

        /**
         * Evaluation order: the API evaluates rules with lower numbers first. Must be
         * unique across the flag's rules.
         */
        priority: number;

        /**
         * Variation the API serves when this rule matches. Must be a key in `variations`.
         */
        serve_variation: string;

        rollout?: Rule.Rollout;
      }

      export namespace Rule {
        export interface UnionMember0 {
          attribute: string;

          operator:
            | 'equals'
            | 'not_equals'
            | 'greater_than'
            | 'less_than'
            | 'greater_than_or_equals'
            | 'less_than_or_equals'
            | 'contains'
            | 'starts_with'
            | 'ends_with'
            | 'in'
            | 'not_in'
            | 'has'
            | 'not_has';

          value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
        }

        export interface UnionMember1 {
          clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

          logical_operator: 'AND' | 'OR';
        }

        export namespace UnionMember1 {
          export interface UnionMember0 {
            attribute: string;

            operator:
              | 'equals'
              | 'not_equals'
              | 'greater_than'
              | 'less_than'
              | 'greater_than_or_equals'
              | 'less_than_or_equals'
              | 'contains'
              | 'starts_with'
              | 'ends_with'
              | 'in'
              | 'not_in'
              | 'has'
              | 'not_has';

            value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
          }

          export interface UnionMember1 {
            clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

            logical_operator: 'AND' | 'OR';
          }

          export namespace UnionMember1 {
            export interface UnionMember0 {
              attribute: string;

              operator:
                | 'equals'
                | 'not_equals'
                | 'greater_than'
                | 'less_than'
                | 'greater_than_or_equals'
                | 'less_than_or_equals'
                | 'contains'
                | 'starts_with'
                | 'ends_with'
                | 'in'
                | 'not_in'
                | 'has'
                | 'not_has';

              value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
            }

            export interface UnionMember1 {
              clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

              logical_operator: 'AND' | 'OR';
            }

            export namespace UnionMember1 {
              export interface UnionMember0 {
                attribute: string;

                operator:
                  | 'equals'
                  | 'not_equals'
                  | 'greater_than'
                  | 'less_than'
                  | 'greater_than_or_equals'
                  | 'less_than_or_equals'
                  | 'contains'
                  | 'starts_with'
                  | 'ends_with'
                  | 'in'
                  | 'not_in'
                  | 'has'
                  | 'not_has';

                value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
              }

              export interface UnionMember1 {
                clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

                logical_operator: 'AND' | 'OR';
              }

              export namespace UnionMember1 {
                export interface UnionMember0 {
                  attribute: string;

                  operator:
                    | 'equals'
                    | 'not_equals'
                    | 'greater_than'
                    | 'less_than'
                    | 'greater_than_or_equals'
                    | 'less_than_or_equals'
                    | 'contains'
                    | 'starts_with'
                    | 'ends_with'
                    | 'in'
                    | 'not_in'
                    | 'has'
                    | 'not_has';

                  value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
                }

                export interface UnionMember1 {
                  clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

                  logical_operator: 'AND' | 'OR';
                }

                export namespace UnionMember1 {
                  export interface UnionMember0 {
                    attribute: string;

                    operator:
                      | 'equals'
                      | 'not_equals'
                      | 'greater_than'
                      | 'less_than'
                      | 'greater_than_or_equals'
                      | 'less_than_or_equals'
                      | 'contains'
                      | 'starts_with'
                      | 'ends_with'
                      | 'in'
                      | 'not_in'
                      | 'has'
                      | 'not_has';

                    value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
                  }

                  export interface UnionMember1 {
                    clauses: Array<
                      string | null | number | boolean | { [key: string]: unknown } | Array<unknown>
                    >;

                    logical_operator: 'AND' | 'OR';
                  }
                }
              }
            }
          }
        }

        export interface Rollout {
          /**
           * Percentage of matching traffic (0–100, up to 2 decimal places) served this
           * variation. For multi-way splits, use cumulative upper bounds across rules (e.g.
           * 30, 70, 100).
           */
          percentage: number;

          /**
           * Context attribute used for sticky bucketing. Defaults to `targetingKey`. If
           * absent at evaluation time, bucketing is random per request.
           */
          attribute?: string;
        }
      }
    }
  }

  export interface UnionMember1 {
    after: UnionMember1.After;

    event: 'delete';

    flag_key: string;
  }

  export namespace UnionMember1 {
    export interface After {
      /**
       * Variation the API serves when the flag is off, or when it's on but no rule
       * matches the context. Must be a key in `variations`.
       */
      default_variation: string;

      /**
       * When false, the flag bypasses all rules and always serves `default_variation`.
       */
      enabled: boolean;

      /**
       * Unique identifier for the flag within an app. Used in all evaluation and SDK
       * calls.
       */
      key: string;

      /**
       * Targeting rules evaluated in ascending `priority`; the first matching rule wins.
       * An empty array means the flag always serves `default_variation`.
       */
      rules: Array<After.Rule>;

      /**
       * Server-inferred value type shared by all of the flag's variations.
       */
      type: 'boolean' | 'string' | 'number' | 'json';

      /**
       * Map of variation name to value. All values share the same type (boolean, string,
       * number, or JSON object/array), and each serialized value stays within 10KB.
       */
      variations: {
        [key: string]: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
      };

      /**
       * Optional operator-facing description. It does not affect flag evaluation.
       */
      description?: string | null;

      updated_at?: string;

      updated_by?: string;
    }

    export namespace After {
      export interface Rule {
        /**
         * Conditions the context must satisfy for this rule to match. An empty array
         * matches all contexts.
         */
        conditions: Array<Rule.UnionMember0 | Rule.UnionMember1>;

        /**
         * Evaluation order: the API evaluates rules with lower numbers first. Must be
         * unique across the flag's rules.
         */
        priority: number;

        /**
         * Variation the API serves when this rule matches. Must be a key in `variations`.
         */
        serve_variation: string;

        rollout?: Rule.Rollout;
      }

      export namespace Rule {
        export interface UnionMember0 {
          attribute: string;

          operator:
            | 'equals'
            | 'not_equals'
            | 'greater_than'
            | 'less_than'
            | 'greater_than_or_equals'
            | 'less_than_or_equals'
            | 'contains'
            | 'starts_with'
            | 'ends_with'
            | 'in'
            | 'not_in'
            | 'has'
            | 'not_has';

          value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
        }

        export interface UnionMember1 {
          clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

          logical_operator: 'AND' | 'OR';
        }

        export namespace UnionMember1 {
          export interface UnionMember0 {
            attribute: string;

            operator:
              | 'equals'
              | 'not_equals'
              | 'greater_than'
              | 'less_than'
              | 'greater_than_or_equals'
              | 'less_than_or_equals'
              | 'contains'
              | 'starts_with'
              | 'ends_with'
              | 'in'
              | 'not_in'
              | 'has'
              | 'not_has';

            value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
          }

          export interface UnionMember1 {
            clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

            logical_operator: 'AND' | 'OR';
          }

          export namespace UnionMember1 {
            export interface UnionMember0 {
              attribute: string;

              operator:
                | 'equals'
                | 'not_equals'
                | 'greater_than'
                | 'less_than'
                | 'greater_than_or_equals'
                | 'less_than_or_equals'
                | 'contains'
                | 'starts_with'
                | 'ends_with'
                | 'in'
                | 'not_in'
                | 'has'
                | 'not_has';

              value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
            }

            export interface UnionMember1 {
              clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

              logical_operator: 'AND' | 'OR';
            }

            export namespace UnionMember1 {
              export interface UnionMember0 {
                attribute: string;

                operator:
                  | 'equals'
                  | 'not_equals'
                  | 'greater_than'
                  | 'less_than'
                  | 'greater_than_or_equals'
                  | 'less_than_or_equals'
                  | 'contains'
                  | 'starts_with'
                  | 'ends_with'
                  | 'in'
                  | 'not_in'
                  | 'has'
                  | 'not_has';

                value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
              }

              export interface UnionMember1 {
                clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

                logical_operator: 'AND' | 'OR';
              }

              export namespace UnionMember1 {
                export interface UnionMember0 {
                  attribute: string;

                  operator:
                    | 'equals'
                    | 'not_equals'
                    | 'greater_than'
                    | 'less_than'
                    | 'greater_than_or_equals'
                    | 'less_than_or_equals'
                    | 'contains'
                    | 'starts_with'
                    | 'ends_with'
                    | 'in'
                    | 'not_in'
                    | 'has'
                    | 'not_has';

                  value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
                }

                export interface UnionMember1 {
                  clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

                  logical_operator: 'AND' | 'OR';
                }

                export namespace UnionMember1 {
                  export interface UnionMember0 {
                    attribute: string;

                    operator:
                      | 'equals'
                      | 'not_equals'
                      | 'greater_than'
                      | 'less_than'
                      | 'greater_than_or_equals'
                      | 'less_than_or_equals'
                      | 'contains'
                      | 'starts_with'
                      | 'ends_with'
                      | 'in'
                      | 'not_in'
                      | 'has'
                      | 'not_has';

                    value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
                  }

                  export interface UnionMember1 {
                    clauses: Array<
                      string | null | number | boolean | { [key: string]: unknown } | Array<unknown>
                    >;

                    logical_operator: 'AND' | 'OR';
                  }
                }
              }
            }
          }
        }

        export interface Rollout {
          /**
           * Percentage of matching traffic (0–100, up to 2 decimal places) served this
           * variation. For multi-way splits, use cumulative upper bounds across rules (e.g.
           * 30, 70, 100).
           */
          percentage: number;

          /**
           * Context attribute used for sticky bucketing. Defaults to `targetingKey`. If
           * absent at evaluation time, bucketing is random per request.
           */
          attribute?: string;
        }
      }
    }
  }

  export interface UnionMember2 {
    after: UnionMember2.After;

    diff: { [key: string]: UnionMember2.Diff };

    event: 'update';

    flag_key: string;
  }

  export namespace UnionMember2 {
    export interface After {
      /**
       * Variation the API serves when the flag is off, or when it's on but no rule
       * matches the context. Must be a key in `variations`.
       */
      default_variation: string;

      /**
       * When false, the flag bypasses all rules and always serves `default_variation`.
       */
      enabled: boolean;

      /**
       * Unique identifier for the flag within an app. Used in all evaluation and SDK
       * calls.
       */
      key: string;

      /**
       * Targeting rules evaluated in ascending `priority`; the first matching rule wins.
       * An empty array means the flag always serves `default_variation`.
       */
      rules: Array<After.Rule>;

      /**
       * Server-inferred value type shared by all of the flag's variations.
       */
      type: 'boolean' | 'string' | 'number' | 'json';

      /**
       * Map of variation name to value. All values share the same type (boolean, string,
       * number, or JSON object/array), and each serialized value stays within 10KB.
       */
      variations: {
        [key: string]: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
      };

      /**
       * Optional operator-facing description. It does not affect flag evaluation.
       */
      description?: string | null;

      updated_at?: string;

      updated_by?: string;
    }

    export namespace After {
      export interface Rule {
        /**
         * Conditions the context must satisfy for this rule to match. An empty array
         * matches all contexts.
         */
        conditions: Array<Rule.UnionMember0 | Rule.UnionMember1>;

        /**
         * Evaluation order: the API evaluates rules with lower numbers first. Must be
         * unique across the flag's rules.
         */
        priority: number;

        /**
         * Variation the API serves when this rule matches. Must be a key in `variations`.
         */
        serve_variation: string;

        rollout?: Rule.Rollout;
      }

      export namespace Rule {
        export interface UnionMember0 {
          attribute: string;

          operator:
            | 'equals'
            | 'not_equals'
            | 'greater_than'
            | 'less_than'
            | 'greater_than_or_equals'
            | 'less_than_or_equals'
            | 'contains'
            | 'starts_with'
            | 'ends_with'
            | 'in'
            | 'not_in'
            | 'has'
            | 'not_has';

          value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
        }

        export interface UnionMember1 {
          clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

          logical_operator: 'AND' | 'OR';
        }

        export namespace UnionMember1 {
          export interface UnionMember0 {
            attribute: string;

            operator:
              | 'equals'
              | 'not_equals'
              | 'greater_than'
              | 'less_than'
              | 'greater_than_or_equals'
              | 'less_than_or_equals'
              | 'contains'
              | 'starts_with'
              | 'ends_with'
              | 'in'
              | 'not_in'
              | 'has'
              | 'not_has';

            value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
          }

          export interface UnionMember1 {
            clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

            logical_operator: 'AND' | 'OR';
          }

          export namespace UnionMember1 {
            export interface UnionMember0 {
              attribute: string;

              operator:
                | 'equals'
                | 'not_equals'
                | 'greater_than'
                | 'less_than'
                | 'greater_than_or_equals'
                | 'less_than_or_equals'
                | 'contains'
                | 'starts_with'
                | 'ends_with'
                | 'in'
                | 'not_in'
                | 'has'
                | 'not_has';

              value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
            }

            export interface UnionMember1 {
              clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

              logical_operator: 'AND' | 'OR';
            }

            export namespace UnionMember1 {
              export interface UnionMember0 {
                attribute: string;

                operator:
                  | 'equals'
                  | 'not_equals'
                  | 'greater_than'
                  | 'less_than'
                  | 'greater_than_or_equals'
                  | 'less_than_or_equals'
                  | 'contains'
                  | 'starts_with'
                  | 'ends_with'
                  | 'in'
                  | 'not_in'
                  | 'has'
                  | 'not_has';

                value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
              }

              export interface UnionMember1 {
                clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

                logical_operator: 'AND' | 'OR';
              }

              export namespace UnionMember1 {
                export interface UnionMember0 {
                  attribute: string;

                  operator:
                    | 'equals'
                    | 'not_equals'
                    | 'greater_than'
                    | 'less_than'
                    | 'greater_than_or_equals'
                    | 'less_than_or_equals'
                    | 'contains'
                    | 'starts_with'
                    | 'ends_with'
                    | 'in'
                    | 'not_in'
                    | 'has'
                    | 'not_has';

                  value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
                }

                export interface UnionMember1 {
                  clauses: Array<UnionMember1.UnionMember0 | UnionMember1.UnionMember1>;

                  logical_operator: 'AND' | 'OR';
                }

                export namespace UnionMember1 {
                  export interface UnionMember0 {
                    attribute: string;

                    operator:
                      | 'equals'
                      | 'not_equals'
                      | 'greater_than'
                      | 'less_than'
                      | 'greater_than_or_equals'
                      | 'less_than_or_equals'
                      | 'contains'
                      | 'starts_with'
                      | 'ends_with'
                      | 'in'
                      | 'not_in'
                      | 'has'
                      | 'not_has';

                    value: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
                  }

                  export interface UnionMember1 {
                    clauses: Array<
                      string | null | number | boolean | { [key: string]: unknown } | Array<unknown>
                    >;

                    logical_operator: 'AND' | 'OR';
                  }
                }
              }
            }
          }
        }

        export interface Rollout {
          /**
           * Percentage of matching traffic (0–100, up to 2 decimal places) served this
           * variation. For multi-way splits, use cumulative upper bounds across rules (e.g.
           * 30, 70, 100).
           */
          percentage: number;

          /**
           * Context attribute used for sticky bucketing. Defaults to `targetingKey`. If
           * absent at evaluation time, bucketing is random per request.
           */
          attribute?: string;
        }
      }
    }

    export interface Diff {
      from?: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;

      to?: string | null | number | boolean | { [key: string]: unknown } | Array<unknown>;
    }
  }
}

export interface ChangelogListParams extends CursorPaginationAfterParams {
  /**
   * Path param: Cloudflare account ID that owns the Flagship app.
   */
  account_id: string;

  /**
   * Path param: Flagship app ID returned when the app was created.
   */
  app_id: string;

  /**
   * Query param: Max items to return (1–200).
   */
  limit?: number;
}

export declare namespace Changelog {
  export {
    type ChangelogListResponse as ChangelogListResponse,
    type ChangelogListResponsesCursorPaginationAfter as ChangelogListResponsesCursorPaginationAfter,
    type ChangelogListParams as ChangelogListParams,
  };
}
