/**
 * Billing Domain - Schemas
 *
 * Zod validation schemas for billing domain types.
 * Used for runtime validation of data from any source.
 */

import { z } from "zod";
import { INVOICE_PAGINATION, VALID_INVOICE_QUERY_STATUSES } from "./constants.js";
import { INVOICE_STATUS } from "./contract.js";

// ============================================================================
// Currency (Domain Model)
// ============================================================================

/**
 * Normalized currency model used across the Portal and BFF.
 * This is intentionally provider-agnostic (even if sourced from WHMCS).
 */
export const currencySchema = z.object({
  id: z.number().int().positive(),
  code: z.string().min(1),
  prefix: z.string(),
  suffix: z.string().optional(),
  format: z.string().optional(),
  rate: z.string().optional(),
});

export type Currency = z.infer<typeof currencySchema>;

// Invoice Status Schema - derived from contract constants
const INVOICE_STATUS_VALUES = Object.values(INVOICE_STATUS) as [string, ...string[]];
export const invoiceStatusSchema = z.enum(INVOICE_STATUS_VALUES);

// Invoice Item Schema
export const invoiceItemSchema = z.object({
  id: z.number().int().positive("Invoice item id must be positive"),
  description: z.string().min(1, "Description is required"),
  amount: z.number(),
  quantity: z.number().int().positive("Quantity must be positive").optional(),
  type: z.string().min(1, "Item type is required"),
  serviceId: z.number().int().positive().optional(),
});

// Invoice Schema
export const invoiceSchema = z.object({
  id: z.number().int().positive("Invoice id must be positive"),
  number: z.string().min(1, "Invoice number is required"),
  status: invoiceStatusSchema,
  currency: z.string().min(1, "Currency is required"),
  currencySymbol: z.string().min(1, "Currency symbol is required").optional(),
  total: z.number(),
  subtotal: z.number(),
  tax: z.number(),
  issuedAt: z.string().optional(),
  dueDate: z.string().optional(),
  paidDate: z.string().optional(),
  pdfUrl: z.string().optional(),
  paymentUrl: z.string().optional(),
  description: z.string().optional(),
  items: z.array(invoiceItemSchema).optional(),
  daysOverdue: z.number().int().nonnegative().optional(),
});

// ============================================================================
// Route Param Schemas (BFF)
// ============================================================================

export const invoiceIdParamSchema = z.object({
  id: z.coerce.number().int().positive("Invoice id must be positive"),
});
export type InvoiceIdParam = z.infer<typeof invoiceIdParamSchema>;

// Invoice Pagination Schema
export const invoicePaginationSchema = z.object({
  page: z.number().int().nonnegative(),
  totalPages: z.number().int().nonnegative(),
  totalItems: z.number().int().nonnegative(),
  nextCursor: z.string().optional(),
});

// Invoice List Schema
export const invoiceListSchema = z.object({
  invoices: z.array(invoiceSchema),
  pagination: invoicePaginationSchema,
});

// Invoice SSO Link Schema
export const invoiceSsoLinkSchema = z.object({
  url: z.string().url(),
  expiresAt: z.string(),
});

// Payment Invoice Request Schema
export const paymentInvoiceRequestSchema = z.object({
  invoiceId: z.number().int().positive(),
  paymentMethodId: z.number().int().positive().optional(),
  gatewayName: z.string().optional(),
  amount: z.number().positive().optional(),
});

// Billing Summary Schema
export const billingSummarySchema = z.object({
  totalOutstanding: z.number(),
  totalOverdue: z.number(),
  totalPaid: z.number(),
  currency: z.string(),
  currencySymbol: z.string().optional(),
  invoiceCount: z.object({
    total: z.number().int().min(0),
    unpaid: z.number().int().min(0),
    overdue: z.number().int().min(0),
    paid: z.number().int().min(0),
  }),
});

// ============================================================================
// Query Parameter Schemas
// ============================================================================

/**
 * Schema for invoice query status - derived from VALID_INVOICE_QUERY_STATUSES constant.
 * Only these 5 statuses can be used to filter invoice lists via WHMCS API.
 */
export const invoiceQueryStatusSchema = z.enum(VALID_INVOICE_QUERY_STATUSES);

/**
 * Schema for invoice list query parameters.
 * Uses invoiceQueryStatusSchema to restrict status to valid WHMCS filter values.
 */
export const invoiceQueryParamsSchema = z.object({
  page: z.coerce
    .number()
    .int()
    .min(INVOICE_PAGINATION.DEFAULT_PAGE)
    .optional()
    .default(INVOICE_PAGINATION.DEFAULT_PAGE),
  limit: z.coerce
    .number()
    .int()
    .min(INVOICE_PAGINATION.MIN_LIMIT)
    .max(INVOICE_PAGINATION.MAX_LIMIT)
    .optional()
    .default(INVOICE_PAGINATION.DEFAULT_LIMIT),
  status: invoiceQueryStatusSchema.optional(),
  dateFrom: z.string().datetime().optional(),
  dateTo: z.string().datetime().optional(),
});

export type InvoiceQueryParams = z.infer<typeof invoiceQueryParamsSchema>;

export const invoiceListQuerySchema = z.object({
  page: z.coerce
    .number()
    .int()
    .min(INVOICE_PAGINATION.DEFAULT_PAGE)
    .optional()
    .default(INVOICE_PAGINATION.DEFAULT_PAGE),
  limit: z.coerce
    .number()
    .int()
    .min(INVOICE_PAGINATION.MIN_LIMIT)
    .max(INVOICE_PAGINATION.MAX_LIMIT)
    .optional()
    .default(INVOICE_PAGINATION.DEFAULT_LIMIT),
  status: invoiceQueryStatusSchema.optional(),
});

export type InvoiceListQuery = z.infer<typeof invoiceListQuerySchema>;

/**
 * Schema for invoice SSO link query parameters
 */
export const invoiceSsoQuerySchema = z.object({
  target: z.enum(["view", "download", "pay"]).optional().default("view"),
});

export type InvoiceSsoQuery = z.infer<typeof invoiceSsoQuerySchema>;

/**
 * Schema for invoice payment link query parameters
 */
export const invoicePaymentLinkQuerySchema = z.object({
  paymentMethodId: z.coerce.number().int().positive().optional(),
  gatewayName: z.string().optional().default("stripe"),
});

export type InvoicePaymentLinkQuery = z.infer<typeof invoicePaymentLinkQuerySchema>;

// ============================================================================
// Inferred Types from Schemas (Schema-First Approach)
// ============================================================================

export type InvoiceStatus = z.infer<typeof invoiceStatusSchema>;
export type InvoiceQueryStatus = z.infer<typeof invoiceQueryStatusSchema>;
export type InvoiceItem = z.infer<typeof invoiceItemSchema>;
export type Invoice = z.infer<typeof invoiceSchema>;
export type InvoicePagination = z.infer<typeof invoicePaginationSchema>;
export type InvoiceList = z.infer<typeof invoiceListSchema>;
export type InvoiceSsoLink = z.infer<typeof invoiceSsoLinkSchema>;
export type PaymentInvoiceRequest = z.infer<typeof paymentInvoiceRequestSchema>;
export type BillingSummary = z.infer<typeof billingSummarySchema>;
