import { queryOneWithRLS, queryWithRLS, mutateWithRLS } from "../db";
const INVOICE_SELECT_COLUMNS = `
  id,
  "teamId",
  "invoiceNumber",
  date,
  amount::NUMERIC(10,2)::FLOAT as amount,
  currency,
  status,
  "pdfUrl",
  description,
  "createdAt",
  "updatedAt"
`;
class InvoiceService {
  // ===========================================
  // QUERIES
  // ===========================================
  /**
   * Get invoice by ID
   *
   * @param id - Invoice ID
   * @returns Invoice or null if not found
   *
   * @example
   * const invoice = await InvoiceService.getById('inv-123')
   */
  static async getById(id) {
    if (!id || id.trim() === "") {
      throw new Error("Invoice ID is required");
    }
    return queryOneWithRLS(
      `SELECT ${INVOICE_SELECT_COLUMNS} FROM "invoices" WHERE id = $1`,
      [id]
    );
  }
  /**
   * Get invoice by invoice number
   *
   * @param invoiceNumber - Invoice number (e.g., 'INV-2024-001')
   * @param teamId - Optional team ID for additional filtering
   * @returns Invoice or null if not found
   *
   * @example
   * const invoice = await InvoiceService.getByNumber('INV-2024-001', 'team-123')
   */
  static async getByNumber(invoiceNumber, teamId) {
    if (!invoiceNumber || invoiceNumber.trim() === "") {
      throw new Error("Invoice number is required");
    }
    if (teamId) {
      return queryOneWithRLS(
        `SELECT ${INVOICE_SELECT_COLUMNS} FROM "invoices"
         WHERE "invoiceNumber" = $1 AND "teamId" = $2`,
        [invoiceNumber, teamId]
      );
    }
    return queryOneWithRLS(
      `SELECT ${INVOICE_SELECT_COLUMNS} FROM "invoices" WHERE "invoiceNumber" = $1`,
      [invoiceNumber]
    );
  }
  /**
   * List invoices for a team with pagination
   *
   * @param teamId - Team ID
   * @param options - List options (limit, offset, status filter)
   * @returns Invoices array and total count
   *
   * @example
   * const { invoices, total } = await InvoiceService.listByTeam('team-123', {
   *   limit: 10,
   *   offset: 0,
   *   status: 'paid'
   * })
   */
  static async listByTeam(teamId, options = {}) {
    var _a;
    if (!teamId || teamId.trim() === "") {
      throw new Error("Team ID is required");
    }
    const { limit = 10, offset = 0, status } = options;
    let query = `SELECT ${INVOICE_SELECT_COLUMNS} FROM "invoices" WHERE "teamId" = $1`;
    let countQuery = `SELECT COUNT(*) as count FROM "invoices" WHERE "teamId" = $1`;
    const params = [teamId];
    if (status) {
      query += ` AND status = $2`;
      countQuery += ` AND status = $2`;
      params.push(status);
    }
    query += ` ORDER BY date DESC LIMIT $${params.length + 1} OFFSET $${params.length + 2}`;
    const invoices = await queryWithRLS(query, [...params, limit, offset]);
    const totalResult = await queryWithRLS(countQuery, params);
    const total = parseInt(((_a = totalResult[0]) == null ? void 0 : _a.count) || "0", 10);
    return { invoices, total };
  }
  /**
   * List invoices for a subscription
   *
   * @param subscriptionId - Subscription ID
   * @returns Array of invoices
   *
   * @example
   * const invoices = await InvoiceService.listBySubscription('sub-123')
   */
  static async listBySubscription(subscriptionId) {
    if (!subscriptionId || subscriptionId.trim() === "") {
      throw new Error("Subscription ID is required");
    }
    const subscription = await queryOneWithRLS(
      `SELECT "teamId" FROM "subscriptions" WHERE id = $1`,
      [subscriptionId]
    );
    if (!subscription) {
      return [];
    }
    return queryWithRLS(
      `SELECT ${INVOICE_SELECT_COLUMNS} FROM "invoices"
       WHERE "teamId" = $1 ORDER BY date DESC`,
      [subscription.teamId]
    );
  }
  /**
   * List overdue invoices (pending and past due date)
   *
   * @param options - Pagination options
   * @returns Array of overdue invoices
   *
   * @example
   * const overdueInvoices = await InvoiceService.listOverdue()
   */
  static async listOverdue(options = {}) {
    const { limit = 100, offset = 0 } = options;
    return queryWithRLS(
      `SELECT ${INVOICE_SELECT_COLUMNS} FROM "invoices"
       WHERE status = 'pending' AND date < NOW()
       ORDER BY date ASC
       LIMIT $1 OFFSET $2`,
      [limit, offset]
    );
  }
  /**
   * List invoices by date range
   *
   * @param startDate - Start date
   * @param endDate - End date
   * @param teamId - Optional team ID to filter
   * @returns Array of invoices within the date range
   *
   * @example
   * const q1Invoices = await InvoiceService.listByDateRange(
   *   new Date('2024-01-01'),
   *   new Date('2024-03-31')
   * )
   */
  static async listByDateRange(startDate, endDate, teamId) {
    if (!startDate || !endDate) {
      throw new Error("Start and end dates are required");
    }
    if (startDate > endDate) {
      throw new Error("Start date must be before end date");
    }
    if (teamId) {
      return queryWithRLS(
        `SELECT ${INVOICE_SELECT_COLUMNS} FROM "invoices"
         WHERE date >= $1 AND date <= $2 AND "teamId" = $3
         ORDER BY date DESC`,
        [startDate.toISOString(), endDate.toISOString(), teamId]
      );
    }
    return queryWithRLS(
      `SELECT ${INVOICE_SELECT_COLUMNS} FROM "invoices"
       WHERE date >= $1 AND date <= $2
       ORDER BY date DESC`,
      [startDate.toISOString(), endDate.toISOString()]
    );
  }
  /**
   * Get the most recent invoice for a team
   *
   * @param teamId - Team ID
   * @returns Most recent invoice or null
   *
   * @example
   * const lastInvoice = await InvoiceService.getLastForTeam('team-123')
   */
  static async getLastForTeam(teamId) {
    if (!teamId || teamId.trim() === "") {
      throw new Error("Team ID is required");
    }
    return queryOneWithRLS(
      `SELECT ${INVOICE_SELECT_COLUMNS} FROM "invoices"
       WHERE "teamId" = $1
       ORDER BY date DESC
       LIMIT 1`,
      [teamId]
    );
  }
  /**
   * Get revenue summary for a period
   *
   * @param year - Year to filter
   * @param month - Optional month to filter (1-12)
   * @returns Revenue summary with totals by status
   *
   * @example
   * const revenue = await InvoiceService.getRevenueSummary(2024)
   * const janRevenue = await InvoiceService.getRevenueSummary(2024, 1)
   */
  static async getRevenueSummary(year, month) {
    let dateFilter = `EXTRACT(YEAR FROM date) = $1`;
    const params = [year];
    if (month) {
      dateFilter += ` AND EXTRACT(MONTH FROM date) = $2`;
      params.push(month);
    }
    const results = await queryWithRLS(
      `SELECT status, COALESCE(SUM(amount), 0)::NUMERIC(10,2)::FLOAT as total
       FROM "invoices"
       WHERE ${dateFilter}
       GROUP BY status`,
      params
    );
    const summary = { paid: 0, pending: 0, failed: 0, total: 0 };
    for (const row of results) {
      if (row.status === "paid") summary.paid = row.total;
      else if (row.status === "pending") summary.pending = row.total;
      else if (row.status === "failed") summary.failed = row.total;
      summary.total += row.total;
    }
    return summary;
  }
  // ===========================================
  // MUTATIONS
  // ===========================================
  /**
   * Create a new invoice
   *
   * @param data - Invoice data
   * @returns Created invoice
   *
   * @example
   * const invoice = await InvoiceService.create({
   *   teamId: 'team-123',
   *   invoiceNumber: 'INV-2024-001',
   *   date: new Date(),
   *   amount: 29.00,
   *   currency: 'USD',
   *   status: 'pending',
   * })
   */
  static async create(data) {
    const { teamId, invoiceNumber, date, amount, currency, status, pdfUrl, description } = data;
    if (!teamId || teamId.trim() === "") {
      throw new Error("Team ID is required");
    }
    if (!invoiceNumber || invoiceNumber.trim() === "") {
      throw new Error("Invoice number is required");
    }
    const result = await mutateWithRLS(
      `
      INSERT INTO "invoices" (
        "teamId",
        "invoiceNumber",
        date,
        amount,
        currency,
        status,
        "pdfUrl",
        description
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
      RETURNING
        id,
        "teamId",
        "invoiceNumber",
        date,
        amount::NUMERIC(10,2)::FLOAT as amount,
        currency,
        status,
        "pdfUrl",
        description,
        "createdAt",
        "updatedAt"
      `,
      [teamId, invoiceNumber, date, amount, currency, status, pdfUrl || null, description || null]
    );
    if (!result.rows[0]) {
      throw new Error("Failed to create invoice");
    }
    return result.rows[0];
  }
  /**
   * Update invoice status
   *
   * @param id - Invoice ID
   * @param status - New status
   * @returns Updated invoice
   *
   * @example
   * const invoice = await InvoiceService.updateStatus('inv-123', 'paid')
   */
  static async updateStatus(id, status) {
    if (!id || id.trim() === "") {
      throw new Error("Invoice ID is required");
    }
    if (!status) {
      throw new Error("Status is required");
    }
    const result = await mutateWithRLS(
      `
      UPDATE "invoices"
      SET status = $2, "updatedAt" = NOW()
      WHERE id = $1
      RETURNING
        id,
        "teamId",
        "invoiceNumber",
        date,
        amount::NUMERIC(10,2)::FLOAT as amount,
        currency,
        status,
        "pdfUrl",
        description,
        "createdAt",
        "updatedAt"
      `,
      [id, status]
    );
    if (!result.rows[0]) {
      throw new Error(`Invoice not found: ${id}`);
    }
    return result.rows[0];
  }
  /**
   * Mark invoice as paid
   *
   * @param id - Invoice ID
   * @param _paymentDetails - Optional payment details (reserved for future use)
   * @returns Updated invoice
   *
   * @example
   * const invoice = await InvoiceService.markAsPaid('inv-123')
   */
  static async markAsPaid(id, _paymentDetails) {
    return this.updateStatus(id, "paid");
  }
  /**
   * Update invoice PDF URL
   *
   * @param id - Invoice ID
   * @param pdfUrl - PDF URL from Stripe
   * @returns Updated invoice
   *
   * @example
   * await InvoiceService.updatePdfUrl('inv-123', 'https://stripe.com/...')
   */
  static async updatePdfUrl(id, pdfUrl) {
    if (!id || id.trim() === "") {
      throw new Error("Invoice ID is required");
    }
    const result = await mutateWithRLS(
      `
      UPDATE "invoices"
      SET "pdfUrl" = $2, "updatedAt" = NOW()
      WHERE id = $1
      RETURNING
        id,
        "teamId",
        "invoiceNumber",
        date,
        amount::NUMERIC(10,2)::FLOAT as amount,
        currency,
        status,
        "pdfUrl",
        description,
        "createdAt",
        "updatedAt"
      `,
      [id, pdfUrl]
    );
    if (!result.rows[0]) {
      throw new Error(`Invoice not found: ${id}`);
    }
    return result.rows[0];
  }
  // ===========================================
  // HELPERS
  // ===========================================
  /**
   * Generate a unique invoice number for a team
   *
   * Format: INV-YYYY-NNNN (e.g., INV-2024-0001)
   *
   * @param teamId - Team ID
   * @returns Generated invoice number
   *
   * @example
   * const number = await InvoiceService.generateNumber('team-123')
   * // 'INV-2024-0001'
   */
  static async generateNumber(teamId) {
    if (!teamId || teamId.trim() === "") {
      throw new Error("Team ID is required");
    }
    const year = (/* @__PURE__ */ new Date()).getFullYear();
    const prefix = `INV-${year}-`;
    const result = await queryOneWithRLS(
      `
      SELECT MAX("invoiceNumber") as "maxNumber"
      FROM "invoices"
      WHERE "teamId" = $1
        AND "invoiceNumber" LIKE $2
      `,
      [teamId, `${prefix}%`]
    );
    let nextNumber = 1;
    if (result == null ? void 0 : result.maxNumber) {
      const currentNumber = parseInt(result.maxNumber.slice(-4), 10);
      if (!isNaN(currentNumber)) {
        nextNumber = currentNumber + 1;
      }
    }
    return `${prefix}${nextNumber.toString().padStart(4, "0")}`;
  }
  /**
   * Get PDF URL for an invoice
   *
   * @param id - Invoice ID
   * @returns PDF URL or null if not available
   *
   * @example
   * const url = await InvoiceService.getPdfUrl('inv-123')
   */
  static async getPdfUrl(id) {
    if (!id || id.trim() === "") {
      return null;
    }
    const invoice = await queryOneWithRLS(
      `SELECT "pdfUrl" FROM "invoices" WHERE id = $1`,
      [id]
    );
    return (invoice == null ? void 0 : invoice.pdfUrl) ?? null;
  }
  /**
   * Check if an invoice exists
   *
   * @param invoiceNumber - Invoice number
   * @param teamId - Team ID
   * @returns True if invoice exists
   *
   * @example
   * const exists = await InvoiceService.exists('INV-2024-0001', 'team-123')
   */
  static async exists(invoiceNumber, teamId) {
    if (!invoiceNumber || !teamId) {
      return false;
    }
    const result = await queryOneWithRLS(
      `SELECT id FROM "invoices" WHERE "invoiceNumber" = $1 AND "teamId" = $2 LIMIT 1`,
      [invoiceNumber, teamId]
    );
    return !!result;
  }
  /**
   * Get total amount for a team's invoices (paid only)
   *
   * @param teamId - Team ID
   * @param year - Optional year filter
   * @returns Total amount in dollars
   *
   * @example
   * const total = await InvoiceService.getTotalPaid('team-123', 2024)
   */
  static async getTotalPaid(teamId, year) {
    if (!teamId || teamId.trim() === "") {
      return 0;
    }
    let query = `
      SELECT COALESCE(SUM(amount), 0)::NUMERIC(10,2)::FLOAT as total
      FROM "invoices"
      WHERE "teamId" = $1 AND status = 'paid'
    `;
    const params = [teamId];
    if (year) {
      query += ` AND EXTRACT(YEAR FROM date) = $2`;
      params.push(year);
    }
    const result = await queryOneWithRLS(query, params);
    return (result == null ? void 0 : result.total) ?? 0;
  }
}
export {
  InvoiceService
};
