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

import * as z from "zod/v3";
import { remap as remap$ } from "../lib/primitives.js";
import { ClosedEnum } from "../types/enums.js";
import { smartUnion } from "../types/smartUnion.js";

/**
 * Period for the billing cycle. The period end date cannot be older than 24 hours earlier than our current server's time.
 */
export type Period = {
  start: Date;
  end: Date;
};

export type BillingItems = {
  /**
   * Partner's billing plan ID.
   */
  billingPlanId: string;
  /**
   * Partner's resource ID.
   */
  resourceId?: string | undefined;
  /**
   * Start and end are only needed if different from the period's start/end.
   */
  start?: Date | undefined;
  /**
   * Start and end are only needed if different from the period's start/end.
   */
  end?: Date | undefined;
  /**
   * Line item name.
   */
  name: string;
  /**
   * Line item details.
   */
  details?: string | undefined;
  /**
   * Price per unit.
   */
  price: string;
  /**
   * Quantity of units.
   */
  quantity: number;
  /**
   * Units of the quantity.
   */
  units: string;
  /**
   * Total amount.
   */
  total: string;
};

export type Discounts = {
  /**
   * Partner's billing plan ID.
   */
  billingPlanId: string;
  /**
   * Partner's resource ID.
   */
  resourceId?: string | undefined;
  /**
   * Start and end are only needed if different from the period's start/end.
   */
  start?: Date | undefined;
  /**
   * Start and end are only needed if different from the period's start/end.
   */
  end?: Date | undefined;
  /**
   * Discount name.
   */
  name: string;
  /**
   * Discount details.
   */
  details?: string | undefined;
  /**
   * Discount amount.
   */
  amount: string;
};

export type Billing2 = {
  items: Array<BillingItems>;
  discounts?: Array<Discounts> | undefined;
};

export type Billing1 = {
  /**
   * Partner's billing plan ID.
   */
  billingPlanId: string;
  /**
   * Partner's resource ID.
   */
  resourceId?: string | undefined;
  /**
   * Start and end are only needed if different from the period's start/end.
   */
  start?: Date | undefined;
  /**
   * Start and end are only needed if different from the period's start/end.
   */
  end?: Date | undefined;
  /**
   * Line item name.
   */
  name: string;
  /**
   * Line item details.
   */
  details?: string | undefined;
  /**
   * Price per unit.
   */
  price: string;
  /**
   * Quantity of units.
   */
  quantity: number;
  /**
   * Units of the quantity.
   */
  units: string;
  /**
   * Total amount.
   */
  total: string;
};

/**
 * Billing data (interim invoicing data).
 */
export type SubmitBillingDataBilling = Billing2 | Array<Billing1>;

/**
 * @remarks
 *               Type of the metric.
 *               - total: measured total value, such as Database size
 *               - interval: usage during the period, such as i/o or number of queries.
 *               - rate: rate of usage, such as queries per second.
 */
export const SubmitBillingDataType = {
  Total: "total",
  Interval: "interval",
  Rate: "rate",
} as const;
/**
 * @remarks
 *               Type of the metric.
 *               - total: measured total value, such as Database size
 *               - interval: usage during the period, such as i/o or number of queries.
 *               - rate: rate of usage, such as queries per second.
 */
export type SubmitBillingDataType = ClosedEnum<typeof SubmitBillingDataType>;

export type Usage = {
  /**
   * Partner's resource ID.
   */
  resourceId?: string | undefined;
  /**
   * Metric name.
   */
  name: string;
  /**
   * @remarks
   *               Type of the metric.
   *               - total: measured total value, such as Database size
   *               - interval: usage during the period, such as i/o or number of queries.
   *               - rate: rate of usage, such as queries per second.
   */
  type: SubmitBillingDataType;
  /**
   * Metric units. Example: "GB"
   */
  units: string;
  /**
   * Metric value for the day. Could be a final or an interim value for the day.
   */
  dayValue: number;
  /**
   * Metric value for the billing period. Could be a final or an interim value for the period.
   */
  periodValue: number;
  /**
   * The limit value of the metric for a billing period, if a limit is defined by the plan.
   */
  planValue?: number | undefined;
};

export type SubmitBillingDataRequestBody = {
  /**
   * Server time of your integration, used to determine the most recent data for race conditions & updates. Only the latest usage data for a given day, week, and month will be kept.
   */
  timestamp: Date;
  /**
   * End of Day, the UTC datetime for when the end of the billing/usage day is in UTC time. This tells us which day the usage data is for, and also allows for your "end of day" to be different from UTC 00:00:00. eod must be within the period dates, and cannot be older than 24h earlier from our server's current time.
   */
  eod: Date;
  /**
   * Period for the billing cycle. The period end date cannot be older than 24 hours earlier than our current server's time.
   */
  period: Period;
  /**
   * Billing data (interim invoicing data).
   */
  billing: Billing2 | Array<Billing1>;
  usage: Array<Usage>;
};

export type SubmitBillingDataRequest = {
  integrationConfigurationId: string;
  requestBody: SubmitBillingDataRequestBody;
};

/** @internal */
export type Period$Outbound = {
  start: string;
  end: string;
};

/** @internal */
export const Period$outboundSchema: z.ZodType<
  Period$Outbound,
  z.ZodTypeDef,
  Period
> = z.object({
  start: z.date().transform(v => v.toISOString()),
  end: z.date().transform(v => v.toISOString()),
});

export function periodToJSON(period: Period): string {
  return JSON.stringify(Period$outboundSchema.parse(period));
}

/** @internal */
export type BillingItems$Outbound = {
  billingPlanId: string;
  resourceId?: string | undefined;
  start?: string | undefined;
  end?: string | undefined;
  name: string;
  details?: string | undefined;
  price: string;
  quantity: number;
  units: string;
  total: string;
};

/** @internal */
export const BillingItems$outboundSchema: z.ZodType<
  BillingItems$Outbound,
  z.ZodTypeDef,
  BillingItems
> = z.object({
  billingPlanId: z.string(),
  resourceId: z.string().optional(),
  start: z.date().transform(v => v.toISOString()).optional(),
  end: z.date().transform(v => v.toISOString()).optional(),
  name: z.string(),
  details: z.string().optional(),
  price: z.string(),
  quantity: z.number(),
  units: z.string(),
  total: z.string(),
});

export function billingItemsToJSON(billingItems: BillingItems): string {
  return JSON.stringify(BillingItems$outboundSchema.parse(billingItems));
}

/** @internal */
export type Discounts$Outbound = {
  billingPlanId: string;
  resourceId?: string | undefined;
  start?: string | undefined;
  end?: string | undefined;
  name: string;
  details?: string | undefined;
  amount: string;
};

/** @internal */
export const Discounts$outboundSchema: z.ZodType<
  Discounts$Outbound,
  z.ZodTypeDef,
  Discounts
> = z.object({
  billingPlanId: z.string(),
  resourceId: z.string().optional(),
  start: z.date().transform(v => v.toISOString()).optional(),
  end: z.date().transform(v => v.toISOString()).optional(),
  name: z.string(),
  details: z.string().optional(),
  amount: z.string(),
});

export function discountsToJSON(discounts: Discounts): string {
  return JSON.stringify(Discounts$outboundSchema.parse(discounts));
}

/** @internal */
export type Billing2$Outbound = {
  items: Array<BillingItems$Outbound>;
  discounts?: Array<Discounts$Outbound> | undefined;
};

/** @internal */
export const Billing2$outboundSchema: z.ZodType<
  Billing2$Outbound,
  z.ZodTypeDef,
  Billing2
> = z.object({
  items: z.array(z.lazy(() => BillingItems$outboundSchema)),
  discounts: z.array(z.lazy(() => Discounts$outboundSchema)).optional(),
});

export function billing2ToJSON(billing2: Billing2): string {
  return JSON.stringify(Billing2$outboundSchema.parse(billing2));
}

/** @internal */
export type Billing1$Outbound = {
  billingPlanId: string;
  resourceId?: string | undefined;
  start?: string | undefined;
  end?: string | undefined;
  name: string;
  details?: string | undefined;
  price: string;
  quantity: number;
  units: string;
  total: string;
};

/** @internal */
export const Billing1$outboundSchema: z.ZodType<
  Billing1$Outbound,
  z.ZodTypeDef,
  Billing1
> = z.object({
  billingPlanId: z.string(),
  resourceId: z.string().optional(),
  start: z.date().transform(v => v.toISOString()).optional(),
  end: z.date().transform(v => v.toISOString()).optional(),
  name: z.string(),
  details: z.string().optional(),
  price: z.string(),
  quantity: z.number(),
  units: z.string(),
  total: z.string(),
});

export function billing1ToJSON(billing1: Billing1): string {
  return JSON.stringify(Billing1$outboundSchema.parse(billing1));
}

/** @internal */
export type SubmitBillingDataBilling$Outbound =
  | Billing2$Outbound
  | Array<Billing1$Outbound>;

/** @internal */
export const SubmitBillingDataBilling$outboundSchema: z.ZodType<
  SubmitBillingDataBilling$Outbound,
  z.ZodTypeDef,
  SubmitBillingDataBilling
> = smartUnion([
  z.lazy(() => Billing2$outboundSchema),
  z.array(z.lazy(() => Billing1$outboundSchema)),
]);

export function submitBillingDataBillingToJSON(
  submitBillingDataBilling: SubmitBillingDataBilling,
): string {
  return JSON.stringify(
    SubmitBillingDataBilling$outboundSchema.parse(submitBillingDataBilling),
  );
}

/** @internal */
export const SubmitBillingDataType$outboundSchema: z.ZodNativeEnum<
  typeof SubmitBillingDataType
> = z.nativeEnum(SubmitBillingDataType);

/** @internal */
export type Usage$Outbound = {
  resourceId?: string | undefined;
  name: string;
  type: string;
  units: string;
  dayValue: number;
  periodValue: number;
  planValue?: number | undefined;
};

/** @internal */
export const Usage$outboundSchema: z.ZodType<
  Usage$Outbound,
  z.ZodTypeDef,
  Usage
> = z.object({
  resourceId: z.string().optional(),
  name: z.string(),
  type: SubmitBillingDataType$outboundSchema,
  units: z.string(),
  dayValue: z.number(),
  periodValue: z.number(),
  planValue: z.number().optional(),
});

export function usageToJSON(usage: Usage): string {
  return JSON.stringify(Usage$outboundSchema.parse(usage));
}

/** @internal */
export type SubmitBillingDataRequestBody$Outbound = {
  timestamp: string;
  eod: string;
  period: Period$Outbound;
  billing: Billing2$Outbound | Array<Billing1$Outbound>;
  usage: Array<Usage$Outbound>;
};

/** @internal */
export const SubmitBillingDataRequestBody$outboundSchema: z.ZodType<
  SubmitBillingDataRequestBody$Outbound,
  z.ZodTypeDef,
  SubmitBillingDataRequestBody
> = z.object({
  timestamp: z.date().transform(v => v.toISOString()),
  eod: z.date().transform(v => v.toISOString()),
  period: z.lazy(() => Period$outboundSchema),
  billing: smartUnion([
    z.lazy(() => Billing2$outboundSchema),
    z.array(z.lazy(() => Billing1$outboundSchema)),
  ]),
  usage: z.array(z.lazy(() => Usage$outboundSchema)),
});

export function submitBillingDataRequestBodyToJSON(
  submitBillingDataRequestBody: SubmitBillingDataRequestBody,
): string {
  return JSON.stringify(
    SubmitBillingDataRequestBody$outboundSchema.parse(
      submitBillingDataRequestBody,
    ),
  );
}

/** @internal */
export type SubmitBillingDataRequest$Outbound = {
  integrationConfigurationId: string;
  RequestBody: SubmitBillingDataRequestBody$Outbound;
};

/** @internal */
export const SubmitBillingDataRequest$outboundSchema: z.ZodType<
  SubmitBillingDataRequest$Outbound,
  z.ZodTypeDef,
  SubmitBillingDataRequest
> = z.object({
  integrationConfigurationId: z.string(),
  requestBody: z.lazy(() => SubmitBillingDataRequestBody$outboundSchema),
}).transform((v) => {
  return remap$(v, {
    requestBody: "RequestBody",
  });
});

export function submitBillingDataRequestToJSON(
  submitBillingDataRequest: SubmitBillingDataRequest,
): string {
  return JSON.stringify(
    SubmitBillingDataRequest$outboundSchema.parse(submitBillingDataRequest),
  );
}
