/**
 * Cliente API — Facturación y Cobranza.
 */
import { api } from '$lib/api';

export * from './catalogs';
export * from './concepts';
export * from './issuer';
export * from './stamping';

export type InvoiceStatus = 'borrador' | 'emitida' | 'enviada' | 'en_revision_cliente' | 'pagada' | 'cancelada';

export interface Invoice {
	id: number;
	reference: string | null;
	shipment_id: number | null;
	quote_id: number | null;
	account_id: number | null;
	currency: string;
	status: InvoiceStatus;
	issue_date: string | null;
	due_date: string | null;
	subtotal: number;
	tax_rate: number;
	tax_amount: number;
	total: number;
	paid_amount: number;
	balance: number;
	ops_cost_total: number | null;
	bank_info: string | null;
	notes: string | null;
	sent_at: string | null;
	paid_at: string | null;
	pdf_file_key: string | null;
	client_reviewed_at: string | null;
	client_approved: boolean | null;
	review_notes: string | null;
	owner_user_id: string | null;
	created_by: string | null;
	updated_by: string | null;
	// Claves fiscales del CFDI (catálogos SAT); nulas mientras no se capturen.
	voucher_type_id: number | null;
	payment_form_id: number | null;
	payment_method_id: number | null;
	expedition_zip_code: string | null;
	/** Modo de timbrado de ESTA factura: 'produccion' emite un CFDI con validez fiscal real. */
	stamping_mode: 'pruebas' | 'produccion';
	tenant_id: number;
	company_id: number;
	created_at: string;
	updated_at: string;
}
export type InvoiceInput = Partial<Omit<Invoice, 'id' | 'status' | 'subtotal' | 'tax_amount' | 'total' | 'paid_amount' | 'balance' | 'sent_at' | 'paid_at' | 'tenant_id' | 'company_id' | 'created_at' | 'updated_at' | 'created_by' | 'updated_by'>>;

export interface InvoiceItem {
	id: number;
	invoice_id: number;
	/** Texto libre que consume el PDF; se hereda del catálogo cuando hay `concept_id`. */
	concept: string;
	description: string | null;
	quantity: number;
	unit_amount: number;
	line_total: number;
	// Claves fiscales de la partida (catálogo de conceptos y catálogos SAT).
	concept_id: number | null;
	product_service_id: number | null;
	unit_of_measure_id: number | null;
	tax_object_id: number | null;
	tenant_id: number;
	company_id: number;
}
/**
 * `concept` es opcional cuando se envía `concept_id`: el backend copia ahí la
 * descripción del concepto del catálogo. Sin ninguno de los dos responde 422.
 */
export type InvoiceItemInput = Partial<Omit<InvoiceItem, 'id' | 'line_total' | 'tenant_id' | 'company_id'>> & {
	invoice_id: number;
};

export interface Payment {
	id: number;
	invoice_id: number;
	amount: number;
	payment_date: string | null;
	method: string | null;
	reference: string | null;
	notes: string | null;
	tenant_id: number;
	company_id: number;
	created_at: string;
}
export type PaymentInput = Partial<Omit<Payment, 'id' | 'tenant_id' | 'company_id' | 'created_at'>> & {
	invoice_id: number;
	amount: number;
};

function qp(companyId: number, extra?: Record<string, string | number | undefined>) {
	const qs = new URLSearchParams({ company_id: String(companyId) });
	for (const [k, v] of Object.entries(extra ?? {})) if (v !== undefined && v !== '') qs.set(k, String(v));
	return qs.toString();
}
async function unwrap<T>(p: Promise<{ data?: T; error?: string }>): Promise<T> {
	const res = await p;
	if (res.error) throw new Error(res.error);
	return res.data as T;
}

export const invoicesAPI = {
	list: (companyId: number, params?: { search?: string; status?: string; account_id?: number }) =>
		unwrap<Invoice[]>(api.get(`/v1/fin/invoices?${qp(companyId, params)}`)),
	get: (id: number, companyId: number) => unwrap<Invoice>(api.get(`/v1/fin/invoices/${id}?${qp(companyId)}`)),
	create: (data: InvoiceInput, companyId: number) => unwrap<Invoice>(api.post(`/v1/fin/invoices?${qp(companyId)}`, data)),
	fromShipment: (shipmentId: number, companyId: number) =>
		unwrap<Invoice>(api.post(`/v1/fin/invoices/from-shipment?${qp(companyId, { shipment_id: shipmentId })}`, {})),
	update: (id: number, data: Partial<InvoiceInput>, companyId: number) => unwrap<Invoice>(api.patch(`/v1/fin/invoices/${id}?${qp(companyId)}`, data)),
	emit: (id: number, companyId: number) => unwrap<Invoice>(api.patch(`/v1/fin/invoices/${id}/emit?${qp(companyId)}`, {})),
	send: (id: number, companyId: number) => unwrap<Invoice>(api.patch(`/v1/fin/invoices/${id}/send?${qp(companyId)}`, {})),
	pdfUrl: (id: number, companyId: number) => unwrap<{ url: string }>(api.get(`/v1/fin/invoices/${id}/pdf-url?${qp(companyId)}`)),
	markClientReview: (id: number, companyId: number) => unwrap<Invoice>(api.patch(`/v1/fin/invoices/${id}/client-review?${qp(companyId)}`, {})),
	clientDecision: (id: number, approved: boolean, companyId: number, notes?: string | null) =>
		unwrap<Invoice>(api.patch(`/v1/fin/invoices/${id}/client-decision?${qp(companyId)}`, { approved, notes })),
	cancel: (id: number, companyId: number) => unwrap<Invoice>(api.patch(`/v1/fin/invoices/${id}/cancel?${qp(companyId)}`, {})),
	remove: (id: number, companyId: number) => unwrap(api.delete(`/v1/fin/invoices/${id}?${qp(companyId)}`)),
	items: (id: number, companyId: number) => unwrap<InvoiceItem[]>(api.get(`/v1/fin/invoices/${id}/items?${qp(companyId)}`)),
	payments: (id: number, companyId: number) => unwrap<Payment[]>(api.get(`/v1/fin/invoices/${id}/payments?${qp(companyId)}`))
};

export const invoiceItemsAPI = {
	create: (data: InvoiceItemInput, companyId: number) => unwrap<InvoiceItem>(api.post(`/v1/fin/invoice-items?${qp(companyId)}`, data)),
	update: (id: number, data: Partial<InvoiceItemInput>, companyId: number) => unwrap<InvoiceItem>(api.patch(`/v1/fin/invoice-items/${id}?${qp(companyId)}`, data)),
	remove: (id: number, companyId: number) => unwrap(api.delete(`/v1/fin/invoice-items/${id}?${qp(companyId)}`))
};

export const paymentsAPI = {
	create: (data: PaymentInput, companyId: number) => unwrap<Payment>(api.post(`/v1/fin/payments?${qp(companyId)}`, data)),
	remove: (id: number, companyId: number) => unwrap(api.delete(`/v1/fin/payments/${id}?${qp(companyId)}`))
};
