/*
 * 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 { safeParse } from "../lib/schemas.js";
import { ClosedEnum } from "../types/enums.js";
import { Result as SafeParseResult } from "../types/fp.js";
import * as types from "../types/primitives.js";
import { SDKValidationError } from "./sdkvalidationerror.js";

/**
 * Subscription period for this billing cycle.
 */
export type SubmitInvoicePeriod = {
  start: Date;
  end: Date;
};

export type SubmitInvoiceItems = {
  /**
   * Partner's resource ID.
   */
  resourceId?: string | undefined;
  /**
   * Partner's billing plan ID.
   */
  billingPlanId: string;
  /**
   * 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;
  name: string;
  details?: string | undefined;
  /**
   * Currency amount as a decimal string.
   */
  price: string;
  quantity: number;
  units: string;
  /**
   * Currency amount as a decimal string.
   */
  total: string;
};

export type SubmitInvoiceDiscounts = {
  /**
   * Partner's resource ID.
   */
  resourceId?: string | undefined;
  /**
   * Partner's billing plan ID.
   */
  billingPlanId: string;
  /**
   * 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;
  name: string;
  details?: string | undefined;
  /**
   * Currency amount as a decimal string.
   */
  amount: string;
};

export const Result = {
  Paid: "paid",
  Notpaid: "notpaid",
  Overdue: "overdue",
} as const;
export type Result = ClosedEnum<typeof Result>;

/**
 * Test mode
 */
export type Test = {
  validate?: boolean | undefined;
  result?: Result | undefined;
};

export type SubmitInvoiceRequestBody = {
  /**
   * Partner-provided invoice identifier. If provided, it must be unique for this installation.
   */
  externalId?: string | undefined;
  /**
   * Invoice date. Must be within the period's start and end.
   */
  invoiceDate: Date;
  /**
   * Additional memo for the invoice.
   */
  memo?: string | undefined;
  /**
   * Subscription period for this billing cycle.
   */
  period: SubmitInvoicePeriod;
  items: Array<SubmitInvoiceItems>;
  discounts?: Array<SubmitInvoiceDiscounts> | undefined;
  /**
   * Set this to `true` if this is the final invoice for the installation. Can only be set when the installation is pending deletion.
   */
  final?: boolean | undefined;
  /**
   * Test mode
   */
  test?: Test | undefined;
};

export type SubmitInvoiceRequest = {
  integrationConfigurationId: string;
  requestBody: SubmitInvoiceRequestBody;
};

export type SubmitInvoiceResponseBody = {
  invoiceId?: string | undefined;
  test?: boolean | undefined;
  validationErrors?: Array<string> | undefined;
};

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

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

export function submitInvoicePeriodToJSON(
  submitInvoicePeriod: SubmitInvoicePeriod,
): string {
  return JSON.stringify(
    SubmitInvoicePeriod$outboundSchema.parse(submitInvoicePeriod),
  );
}

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

/** @internal */
export const SubmitInvoiceItems$outboundSchema: z.ZodType<
  SubmitInvoiceItems$Outbound,
  z.ZodTypeDef,
  SubmitInvoiceItems
> = z.object({
  resourceId: z.string().optional(),
  billingPlanId: z.string(),
  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 submitInvoiceItemsToJSON(
  submitInvoiceItems: SubmitInvoiceItems,
): string {
  return JSON.stringify(
    SubmitInvoiceItems$outboundSchema.parse(submitInvoiceItems),
  );
}

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

/** @internal */
export const SubmitInvoiceDiscounts$outboundSchema: z.ZodType<
  SubmitInvoiceDiscounts$Outbound,
  z.ZodTypeDef,
  SubmitInvoiceDiscounts
> = z.object({
  resourceId: z.string().optional(),
  billingPlanId: z.string(),
  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 submitInvoiceDiscountsToJSON(
  submitInvoiceDiscounts: SubmitInvoiceDiscounts,
): string {
  return JSON.stringify(
    SubmitInvoiceDiscounts$outboundSchema.parse(submitInvoiceDiscounts),
  );
}

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

/** @internal */
export type Test$Outbound = {
  validate?: boolean | undefined;
  result?: string | undefined;
};

/** @internal */
export const Test$outboundSchema: z.ZodType<Test$Outbound, z.ZodTypeDef, Test> =
  z.object({
    validate: z.boolean().optional(),
    result: Result$outboundSchema.optional(),
  });

export function testToJSON(test: Test): string {
  return JSON.stringify(Test$outboundSchema.parse(test));
}

/** @internal */
export type SubmitInvoiceRequestBody$Outbound = {
  externalId?: string | undefined;
  invoiceDate: string;
  memo?: string | undefined;
  period: SubmitInvoicePeriod$Outbound;
  items: Array<SubmitInvoiceItems$Outbound>;
  discounts?: Array<SubmitInvoiceDiscounts$Outbound> | undefined;
  final?: boolean | undefined;
  test?: Test$Outbound | undefined;
};

/** @internal */
export const SubmitInvoiceRequestBody$outboundSchema: z.ZodType<
  SubmitInvoiceRequestBody$Outbound,
  z.ZodTypeDef,
  SubmitInvoiceRequestBody
> = z.object({
  externalId: z.string().optional(),
  invoiceDate: z.date().transform(v => v.toISOString()),
  memo: z.string().optional(),
  period: z.lazy(() => SubmitInvoicePeriod$outboundSchema),
  items: z.array(z.lazy(() => SubmitInvoiceItems$outboundSchema)),
  discounts: z.array(z.lazy(() => SubmitInvoiceDiscounts$outboundSchema))
    .optional(),
  final: z.boolean().optional(),
  test: z.lazy(() => Test$outboundSchema).optional(),
});

export function submitInvoiceRequestBodyToJSON(
  submitInvoiceRequestBody: SubmitInvoiceRequestBody,
): string {
  return JSON.stringify(
    SubmitInvoiceRequestBody$outboundSchema.parse(submitInvoiceRequestBody),
  );
}

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

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

export function submitInvoiceRequestToJSON(
  submitInvoiceRequest: SubmitInvoiceRequest,
): string {
  return JSON.stringify(
    SubmitInvoiceRequest$outboundSchema.parse(submitInvoiceRequest),
  );
}

/** @internal */
export const SubmitInvoiceResponseBody$inboundSchema: z.ZodType<
  SubmitInvoiceResponseBody,
  z.ZodTypeDef,
  unknown
> = z.object({
  invoiceId: types.optional(types.string()),
  test: types.optional(types.boolean()),
  validationErrors: types.optional(z.array(types.string())),
});

export function submitInvoiceResponseBodyFromJSON(
  jsonString: string,
): SafeParseResult<SubmitInvoiceResponseBody, SDKValidationError> {
  return safeParse(
    jsonString,
    (x) => SubmitInvoiceResponseBody$inboundSchema.parse(JSON.parse(x)),
    `Failed to parse 'SubmitInvoiceResponseBody' from JSON`,
  );
}
