/*
 * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
 */

import * as z from "zod/v4-mini";
import { remap as remap$ } from "../../lib/primitives.js";
import { safeParse } from "../../lib/schemas.js";
import { Result as SafeParseResult } from "../../types/fp.js";
import { smartUnion } from "../../types/smartUnion.js";
import { SDKValidationError } from "../errors/sdkvalidationerror.js";
import {
  CustomerCancellationReason,
  CustomerCancellationReason$inboundSchema,
  CustomerCancellationReason$outboundSchema,
} from "./customercancellationreason.js";
import {
  DiscountFixedOnceForeverDurationBase,
  DiscountFixedOnceForeverDurationBase$inboundSchema,
  DiscountFixedOnceForeverDurationBase$Outbound,
  DiscountFixedOnceForeverDurationBase$outboundSchema,
} from "./discountfixedonceforeverdurationbase.js";
import {
  DiscountFixedRepeatDurationBase,
  DiscountFixedRepeatDurationBase$inboundSchema,
  DiscountFixedRepeatDurationBase$Outbound,
  DiscountFixedRepeatDurationBase$outboundSchema,
} from "./discountfixedrepeatdurationbase.js";
import {
  DiscountPercentageOnceForeverDurationBase,
  DiscountPercentageOnceForeverDurationBase$inboundSchema,
  DiscountPercentageOnceForeverDurationBase$Outbound,
  DiscountPercentageOnceForeverDurationBase$outboundSchema,
} from "./discountpercentageonceforeverdurationbase.js";
import {
  DiscountPercentageRepeatDurationBase,
  DiscountPercentageRepeatDurationBase$inboundSchema,
  DiscountPercentageRepeatDurationBase$Outbound,
  DiscountPercentageRepeatDurationBase$outboundSchema,
} from "./discountpercentagerepeatdurationbase.js";
import {
  LegacyRecurringProductPrice,
  LegacyRecurringProductPrice$inboundSchema,
  LegacyRecurringProductPrice$Outbound,
  LegacyRecurringProductPrice$outboundSchema,
} from "./legacyrecurringproductprice.js";
import {
  MetadataOutputType,
  MetadataOutputType$inboundSchema,
  MetadataOutputType$Outbound,
  MetadataOutputType$outboundSchema,
} from "./metadataoutputtype.js";
import {
  PendingSubscriptionUpdate,
  PendingSubscriptionUpdate$inboundSchema,
  PendingSubscriptionUpdate$Outbound,
  PendingSubscriptionUpdate$outboundSchema,
} from "./pendingsubscriptionupdate.js";
import {
  Product,
  Product$inboundSchema,
  Product$Outbound,
  Product$outboundSchema,
} from "./product.js";
import {
  ProductPrice,
  ProductPrice$inboundSchema,
  ProductPrice$Outbound,
  ProductPrice$outboundSchema,
} from "./productprice.js";
import {
  RecurringInterval,
  RecurringInterval$inboundSchema,
  RecurringInterval$outboundSchema,
} from "./recurringinterval.js";
import {
  SubscriptionCustomer,
  SubscriptionCustomer$inboundSchema,
  SubscriptionCustomer$Outbound,
  SubscriptionCustomer$outboundSchema,
} from "./subscriptioncustomer.js";
import {
  SubscriptionMeter,
  SubscriptionMeter$inboundSchema,
  SubscriptionMeter$Outbound,
  SubscriptionMeter$outboundSchema,
} from "./subscriptionmeter.js";
import {
  SubscriptionStatus,
  SubscriptionStatus$inboundSchema,
  SubscriptionStatus$outboundSchema,
} from "./subscriptionstatus.js";

export type CustomFieldData = string | number | boolean | Date;

export type SubscriptionDiscount =
  | DiscountFixedRepeatDurationBase
  | DiscountFixedOnceForeverDurationBase
  | DiscountPercentageRepeatDurationBase
  | DiscountPercentageOnceForeverDurationBase;

export type SubscriptionPrices = LegacyRecurringProductPrice | ProductPrice;

export type Subscription = {
  /**
   * Creation timestamp of the object.
   */
  createdAt: Date;
  /**
   * Last modification timestamp of the object.
   */
  modifiedAt: Date | null;
  /**
   * The ID of the object.
   */
  id: string;
  /**
   * The amount of the subscription.
   */
  amount: number;
  /**
   * The currency of the subscription.
   */
  currency: string;
  recurringInterval: RecurringInterval;
  /**
   * Number of interval units of the subscription. If this is set to 1 the charge will happen every interval (e.g. every month), if set to 2 it will be every other month, and so on.
   */
  recurringIntervalCount: number;
  status: SubscriptionStatus;
  /**
   * The start timestamp of the current billing period.
   */
  currentPeriodStart: Date;
  /**
   * The end timestamp of the current billing period.
   */
  currentPeriodEnd: Date;
  /**
   * The start timestamp of the current meter period, if the product has a meter cycle set. Metered credits are granted and overage is settled on this cadence.
   */
  currentMeterPeriodStart: Date | null;
  /**
   * The end timestamp of the current meter period, if the product has a meter cycle set. This is when credits next renew.
   */
  currentMeterPeriodEnd: Date | null;
  /**
   * The start timestamp of the trial period, if any.
   */
  trialStart: Date | null;
  /**
   * The end timestamp of the trial period, if any.
   */
  trialEnd: Date | null;
  /**
   * Whether the subscription will be canceled at the end of the current period.
   */
  cancelAtPeriodEnd: boolean;
  /**
   * The timestamp when the subscription was canceled. The subscription might still be active if `cancel_at_period_end` is `true`.
   */
  canceledAt: Date | null;
  /**
   * The timestamp when the subscription started.
   */
  startedAt: Date | null;
  /**
   * The timestamp when the subscription will end.
   */
  endsAt: Date | null;
  /**
   * The timestamp when the subscription ended.
   */
  endedAt: Date | null;
  /**
   * The timestamp when the subscription entered `past_due` status.
   */
  pastDueAt?: Date | null | undefined;
  /**
   * Whether the subscription will be paused at the end of the current period.
   */
  pauseAtPeriodEnd: boolean;
  /**
   * The timestamp when the subscription was paused.
   */
  pausedAt: Date | null;
  /**
   * The timestamp when a paused subscription is scheduled to automatically resume, if set.
   */
  resumesAt: Date | null;
  /**
   * The ID of the subscribed customer.
   */
  customerId: string;
  /**
   * The ID of the subscribed product.
   */
  productId: string;
  /**
   * The ID of the applied discount, if any.
   */
  discountId: string | null;
  checkoutId: string | null;
  /**
   * The number of seats for seat-based subscriptions. None for non-seat subscriptions.
   */
  seats?: number | null | undefined;
  customerCancellationReason: CustomerCancellationReason | null;
  customerCancellationComment: string | null;
  metadata: { [k: string]: MetadataOutputType };
  /**
   * Key-value object storing custom field values.
   */
  customFieldData?:
    | { [k: string]: string | number | boolean | Date | null }
    | undefined;
  customer: SubscriptionCustomer;
  /**
   * A product.
   */
  product: Product;
  discount:
    | DiscountFixedRepeatDurationBase
    | DiscountFixedOnceForeverDurationBase
    | DiscountPercentageRepeatDurationBase
    | DiscountPercentageOnceForeverDurationBase
    | null;
  /**
   * List of enabled prices for the subscription.
   */
  prices: Array<LegacyRecurringProductPrice | ProductPrice>;
  /**
   * List of meters associated with the subscription.
   */
  meters: Array<SubscriptionMeter>;
  /**
   * Pending subscription update that will be applied at the beginning of the next period. If `null`, there is no pending update.
   */
  pendingUpdate: PendingSubscriptionUpdate | null;
};

/** @internal */
export const CustomFieldData$inboundSchema: z.ZodMiniType<
  CustomFieldData,
  unknown
> = smartUnion([
  z.string(),
  z.int(),
  z.boolean(),
  z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
]);
/** @internal */
export type CustomFieldData$Outbound = string | number | boolean | string;

/** @internal */
export const CustomFieldData$outboundSchema: z.ZodMiniType<
  CustomFieldData$Outbound,
  CustomFieldData
> = smartUnion([
  z.string(),
  z.int(),
  z.boolean(),
  z.pipe(z.date(), z.transform(v => v.toISOString())),
]);

export function customFieldDataToJSON(
  customFieldData: CustomFieldData,
): string {
  return JSON.stringify(CustomFieldData$outboundSchema.parse(customFieldData));
}
export function customFieldDataFromJSON(
  jsonString: string,
): SafeParseResult<CustomFieldData, SDKValidationError> {
  return safeParse(
    jsonString,
    (x) => CustomFieldData$inboundSchema.parse(JSON.parse(x)),
    `Failed to parse 'CustomFieldData' from JSON`,
  );
}

/** @internal */
export const SubscriptionDiscount$inboundSchema: z.ZodMiniType<
  SubscriptionDiscount,
  unknown
> = smartUnion([
  DiscountFixedRepeatDurationBase$inboundSchema,
  DiscountFixedOnceForeverDurationBase$inboundSchema,
  DiscountPercentageRepeatDurationBase$inboundSchema,
  DiscountPercentageOnceForeverDurationBase$inboundSchema,
]);
/** @internal */
export type SubscriptionDiscount$Outbound =
  | DiscountFixedRepeatDurationBase$Outbound
  | DiscountFixedOnceForeverDurationBase$Outbound
  | DiscountPercentageRepeatDurationBase$Outbound
  | DiscountPercentageOnceForeverDurationBase$Outbound;

/** @internal */
export const SubscriptionDiscount$outboundSchema: z.ZodMiniType<
  SubscriptionDiscount$Outbound,
  SubscriptionDiscount
> = smartUnion([
  DiscountFixedRepeatDurationBase$outboundSchema,
  DiscountFixedOnceForeverDurationBase$outboundSchema,
  DiscountPercentageRepeatDurationBase$outboundSchema,
  DiscountPercentageOnceForeverDurationBase$outboundSchema,
]);

export function subscriptionDiscountToJSON(
  subscriptionDiscount: SubscriptionDiscount,
): string {
  return JSON.stringify(
    SubscriptionDiscount$outboundSchema.parse(subscriptionDiscount),
  );
}
export function subscriptionDiscountFromJSON(
  jsonString: string,
): SafeParseResult<SubscriptionDiscount, SDKValidationError> {
  return safeParse(
    jsonString,
    (x) => SubscriptionDiscount$inboundSchema.parse(JSON.parse(x)),
    `Failed to parse 'SubscriptionDiscount' from JSON`,
  );
}

/** @internal */
export const SubscriptionPrices$inboundSchema: z.ZodMiniType<
  SubscriptionPrices,
  unknown
> = smartUnion([
  LegacyRecurringProductPrice$inboundSchema,
  ProductPrice$inboundSchema,
]);
/** @internal */
export type SubscriptionPrices$Outbound =
  | LegacyRecurringProductPrice$Outbound
  | ProductPrice$Outbound;

/** @internal */
export const SubscriptionPrices$outboundSchema: z.ZodMiniType<
  SubscriptionPrices$Outbound,
  SubscriptionPrices
> = smartUnion([
  LegacyRecurringProductPrice$outboundSchema,
  ProductPrice$outboundSchema,
]);

export function subscriptionPricesToJSON(
  subscriptionPrices: SubscriptionPrices,
): string {
  return JSON.stringify(
    SubscriptionPrices$outboundSchema.parse(subscriptionPrices),
  );
}
export function subscriptionPricesFromJSON(
  jsonString: string,
): SafeParseResult<SubscriptionPrices, SDKValidationError> {
  return safeParse(
    jsonString,
    (x) => SubscriptionPrices$inboundSchema.parse(JSON.parse(x)),
    `Failed to parse 'SubscriptionPrices' from JSON`,
  );
}

/** @internal */
export const Subscription$inboundSchema: z.ZodMiniType<Subscription, unknown> =
  z.pipe(
    z.object({
      created_at: z.pipe(
        z.iso.datetime({ offset: true }),
        z.transform(v => new Date(v)),
      ),
      modified_at: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      id: z.string(),
      amount: z.int(),
      currency: z.string(),
      recurring_interval: RecurringInterval$inboundSchema,
      recurring_interval_count: z.int(),
      status: SubscriptionStatus$inboundSchema,
      current_period_start: z.pipe(
        z.iso.datetime({ offset: true }),
        z.transform(v => new Date(v)),
      ),
      current_period_end: z.pipe(
        z.iso.datetime({ offset: true }),
        z.transform(v => new Date(v)),
      ),
      current_meter_period_start: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      current_meter_period_end: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      trial_start: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      trial_end: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      cancel_at_period_end: z.boolean(),
      canceled_at: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      started_at: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      ends_at: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      ended_at: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      past_due_at: z.optional(
        z.nullable(z.pipe(
          z.iso.datetime({ offset: true }),
          z.transform(v => new Date(v)),
        )),
      ),
      pause_at_period_end: z.boolean(),
      paused_at: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      resumes_at: z.nullable(
        z.pipe(z.iso.datetime({ offset: true }), z.transform(v => new Date(v))),
      ),
      customer_id: z.string(),
      product_id: z.string(),
      discount_id: z.nullable(z.string()),
      checkout_id: z.nullable(z.string()),
      seats: z.optional(z.nullable(z.int())),
      customer_cancellation_reason: z.nullable(
        CustomerCancellationReason$inboundSchema,
      ),
      customer_cancellation_comment: z.nullable(z.string()),
      metadata: z.record(z.string(), MetadataOutputType$inboundSchema),
      custom_field_data: z.optional(
        z.record(
          z.string(),
          z.nullable(
            smartUnion([
              z.string(),
              z.int(),
              z.boolean(),
              z.pipe(
                z.iso.datetime({ offset: true }),
                z.transform(v => new Date(v)),
              ),
            ]),
          ),
        ),
      ),
      customer: SubscriptionCustomer$inboundSchema,
      product: Product$inboundSchema,
      discount: z.nullable(
        smartUnion([
          DiscountFixedRepeatDurationBase$inboundSchema,
          DiscountFixedOnceForeverDurationBase$inboundSchema,
          DiscountPercentageRepeatDurationBase$inboundSchema,
          DiscountPercentageOnceForeverDurationBase$inboundSchema,
        ]),
      ),
      prices: z.array(
        smartUnion([
          LegacyRecurringProductPrice$inboundSchema,
          ProductPrice$inboundSchema,
        ]),
      ),
      meters: z.array(SubscriptionMeter$inboundSchema),
      pending_update: z.nullable(PendingSubscriptionUpdate$inboundSchema),
    }),
    z.transform((v) => {
      return remap$(v, {
        "created_at": "createdAt",
        "modified_at": "modifiedAt",
        "recurring_interval": "recurringInterval",
        "recurring_interval_count": "recurringIntervalCount",
        "current_period_start": "currentPeriodStart",
        "current_period_end": "currentPeriodEnd",
        "current_meter_period_start": "currentMeterPeriodStart",
        "current_meter_period_end": "currentMeterPeriodEnd",
        "trial_start": "trialStart",
        "trial_end": "trialEnd",
        "cancel_at_period_end": "cancelAtPeriodEnd",
        "canceled_at": "canceledAt",
        "started_at": "startedAt",
        "ends_at": "endsAt",
        "ended_at": "endedAt",
        "past_due_at": "pastDueAt",
        "pause_at_period_end": "pauseAtPeriodEnd",
        "paused_at": "pausedAt",
        "resumes_at": "resumesAt",
        "customer_id": "customerId",
        "product_id": "productId",
        "discount_id": "discountId",
        "checkout_id": "checkoutId",
        "customer_cancellation_reason": "customerCancellationReason",
        "customer_cancellation_comment": "customerCancellationComment",
        "custom_field_data": "customFieldData",
        "pending_update": "pendingUpdate",
      });
    }),
  );
/** @internal */
export type Subscription$Outbound = {
  created_at: string;
  modified_at: string | null;
  id: string;
  amount: number;
  currency: string;
  recurring_interval: string;
  recurring_interval_count: number;
  status: string;
  current_period_start: string;
  current_period_end: string;
  current_meter_period_start: string | null;
  current_meter_period_end: string | null;
  trial_start: string | null;
  trial_end: string | null;
  cancel_at_period_end: boolean;
  canceled_at: string | null;
  started_at: string | null;
  ends_at: string | null;
  ended_at: string | null;
  past_due_at?: string | null | undefined;
  pause_at_period_end: boolean;
  paused_at: string | null;
  resumes_at: string | null;
  customer_id: string;
  product_id: string;
  discount_id: string | null;
  checkout_id: string | null;
  seats?: number | null | undefined;
  customer_cancellation_reason: string | null;
  customer_cancellation_comment: string | null;
  metadata: { [k: string]: MetadataOutputType$Outbound };
  custom_field_data?:
    | { [k: string]: string | number | boolean | string | null }
    | undefined;
  customer: SubscriptionCustomer$Outbound;
  product: Product$Outbound;
  discount:
    | DiscountFixedRepeatDurationBase$Outbound
    | DiscountFixedOnceForeverDurationBase$Outbound
    | DiscountPercentageRepeatDurationBase$Outbound
    | DiscountPercentageOnceForeverDurationBase$Outbound
    | null;
  prices: Array<LegacyRecurringProductPrice$Outbound | ProductPrice$Outbound>;
  meters: Array<SubscriptionMeter$Outbound>;
  pending_update: PendingSubscriptionUpdate$Outbound | null;
};

/** @internal */
export const Subscription$outboundSchema: z.ZodMiniType<
  Subscription$Outbound,
  Subscription
> = z.pipe(
  z.object({
    createdAt: z.pipe(z.date(), z.transform(v => v.toISOString())),
    modifiedAt: z.nullable(z.pipe(z.date(), z.transform(v => v.toISOString()))),
    id: z.string(),
    amount: z.int(),
    currency: z.string(),
    recurringInterval: RecurringInterval$outboundSchema,
    recurringIntervalCount: z.int(),
    status: SubscriptionStatus$outboundSchema,
    currentPeriodStart: z.pipe(z.date(), z.transform(v => v.toISOString())),
    currentPeriodEnd: z.pipe(z.date(), z.transform(v => v.toISOString())),
    currentMeterPeriodStart: z.nullable(
      z.pipe(z.date(), z.transform(v => v.toISOString())),
    ),
    currentMeterPeriodEnd: z.nullable(
      z.pipe(z.date(), z.transform(v => v.toISOString())),
    ),
    trialStart: z.nullable(z.pipe(z.date(), z.transform(v => v.toISOString()))),
    trialEnd: z.nullable(z.pipe(z.date(), z.transform(v => v.toISOString()))),
    cancelAtPeriodEnd: z.boolean(),
    canceledAt: z.nullable(z.pipe(z.date(), z.transform(v => v.toISOString()))),
    startedAt: z.nullable(z.pipe(z.date(), z.transform(v => v.toISOString()))),
    endsAt: z.nullable(z.pipe(z.date(), z.transform(v => v.toISOString()))),
    endedAt: z.nullable(z.pipe(z.date(), z.transform(v => v.toISOString()))),
    pastDueAt: z.optional(
      z.nullable(z.pipe(z.date(), z.transform(v => v.toISOString()))),
    ),
    pauseAtPeriodEnd: z.boolean(),
    pausedAt: z.nullable(z.pipe(z.date(), z.transform(v => v.toISOString()))),
    resumesAt: z.nullable(z.pipe(z.date(), z.transform(v => v.toISOString()))),
    customerId: z.string(),
    productId: z.string(),
    discountId: z.nullable(z.string()),
    checkoutId: z.nullable(z.string()),
    seats: z.optional(z.nullable(z.int())),
    customerCancellationReason: z.nullable(
      CustomerCancellationReason$outboundSchema,
    ),
    customerCancellationComment: z.nullable(z.string()),
    metadata: z.record(z.string(), MetadataOutputType$outboundSchema),
    customFieldData: z.optional(
      z.record(
        z.string(),
        z.nullable(
          smartUnion([
            z.string(),
            z.int(),
            z.boolean(),
            z.pipe(z.date(), z.transform(v => v.toISOString())),
          ]),
        ),
      ),
    ),
    customer: SubscriptionCustomer$outboundSchema,
    product: Product$outboundSchema,
    discount: z.nullable(
      smartUnion([
        DiscountFixedRepeatDurationBase$outboundSchema,
        DiscountFixedOnceForeverDurationBase$outboundSchema,
        DiscountPercentageRepeatDurationBase$outboundSchema,
        DiscountPercentageOnceForeverDurationBase$outboundSchema,
      ]),
    ),
    prices: z.array(
      smartUnion([
        LegacyRecurringProductPrice$outboundSchema,
        ProductPrice$outboundSchema,
      ]),
    ),
    meters: z.array(SubscriptionMeter$outboundSchema),
    pendingUpdate: z.nullable(PendingSubscriptionUpdate$outboundSchema),
  }),
  z.transform((v) => {
    return remap$(v, {
      createdAt: "created_at",
      modifiedAt: "modified_at",
      recurringInterval: "recurring_interval",
      recurringIntervalCount: "recurring_interval_count",
      currentPeriodStart: "current_period_start",
      currentPeriodEnd: "current_period_end",
      currentMeterPeriodStart: "current_meter_period_start",
      currentMeterPeriodEnd: "current_meter_period_end",
      trialStart: "trial_start",
      trialEnd: "trial_end",
      cancelAtPeriodEnd: "cancel_at_period_end",
      canceledAt: "canceled_at",
      startedAt: "started_at",
      endsAt: "ends_at",
      endedAt: "ended_at",
      pastDueAt: "past_due_at",
      pauseAtPeriodEnd: "pause_at_period_end",
      pausedAt: "paused_at",
      resumesAt: "resumes_at",
      customerId: "customer_id",
      productId: "product_id",
      discountId: "discount_id",
      checkoutId: "checkout_id",
      customerCancellationReason: "customer_cancellation_reason",
      customerCancellationComment: "customer_cancellation_comment",
      customFieldData: "custom_field_data",
      pendingUpdate: "pending_update",
    });
  }),
);

export function subscriptionToJSON(subscription: Subscription): string {
  return JSON.stringify(Subscription$outboundSchema.parse(subscription));
}
export function subscriptionFromJSON(
  jsonString: string,
): SafeParseResult<Subscription, SDKValidationError> {
  return safeParse(
    jsonString,
    (x) => Subscription$inboundSchema.parse(JSON.parse(x)),
    `Failed to parse 'Subscription' from JSON`,
  );
}
