import { WAVE_ACCESS_TOKEN } from '$env/static/private';
import { PUBLIC_WAVE_BUSINESS_ID } from '$env/static/public';
import { error, fail } from '@sveltejs/kit';
import {
	deleteWaveInvoice,
	sendWaveInvoice,
	updateWaveInvoice,
	approveWaveInvoice
} from '$lib/graphql/wave/mutations';
import type { PageServerLoad, Actions } from './$types';

const WAVE_API_URL = 'https://gql.waveapps.com/graphql/public';

const GET_PRODUCTS_QUERY = `
	query GetProducts($businessId: ID!, $pageSize: Int!) {
		business(id: $businessId) {
			products(page: 1, pageSize: $pageSize, isSold: true, isArchived: false) {
				edges {
					node {
						id
						name
						description
						unitPrice
						isArchived
					}
				}
			}
		}
	}
`;

interface WaveProduct {
	id: string;
	name: string;
	description: string | null;
	unitPrice: number;
	isArchived: boolean;
}

const GET_INVOICE_QUERY = `
	query GetInvoice($businessId: ID!, $invoiceId: ID!) {
		business(id: $businessId) {
			id
			invoice(id: $invoiceId) {
				id
				invoiceNumber
				invoiceDate
				dueDate
				status
				title
				subhead
				poNumber
				memo
				footer
				pdfUrl
				viewUrl
				customer {
					id
					name
					firstName
					lastName
					email
					address {
						addressLine1
						addressLine2
						city
						province {
							code
							name
						}
						country {
							code
							name
						}
						postalCode
					}
				}
				items {
					product {
						id
						name
					}
					description
					quantity
					unitPrice
					subtotal {
						value
						currency {
							code
						}
					}
					total {
						value
						currency {
							code
						}
					}
					taxes {
						salesTax {
							id
							name
							abbreviation
						}
						amount {
							value
							currency {
								code
							}
						}
					}
				}
				discounts {
					... on FixedInvoiceDiscount {
						name
						amount
					}
					... on PercentageInvoiceDiscount {
						name
						percentage
					}
				}
				subtotal {
					value
					currency {
						code
						symbol
					}
				}
				taxTotal {
					value
					currency {
						code
						symbol
					}
				}
				discountTotal {
					value
					currency {
						code
						symbol
					}
				}
				total {
					value
					currency {
						code
						symbol
					}
				}
				amountDue {
					value
					currency {
						code
						symbol
					}
				}
				amountPaid {
					value
					currency {
						code
						symbol
					}
				}
				currency {
					code
					symbol
					name
				}
				exchangeRate
				createdAt
				modifiedAt
				lastSentAt
				lastSentVia
				lastViewedAt
			}
		}
	}
`;

interface WaveInvoiceItem {
	product: {
		id: string;
		name: string;
	} | null;
	description: string | null;
	quantity: string;
	unitPrice: string;
	subtotal: {
		value: string;
		currency: { code: string };
	};
	total: {
		value: string;
		currency: { code: string };
	};
	taxes: Array<{
		salesTax: {
			id: string;
			name: string;
			abbreviation: string;
		};
		amount: {
			value: string;
			currency: { code: string };
		};
	}>;
}

interface WaveInvoiceDiscount {
	name: string;
	amount?: string;
	percentage?: number;
}

interface WaveInvoice {
	id: string;
	invoiceNumber: string;
	invoiceDate: string;
	dueDate: string;
	status: string;
	title: string | null;
	subhead: string | null;
	poNumber: string | null;
	memo: string | null;
	footer: string | null;
	pdfUrl: string | null;
	viewUrl: string | null;
	customer: {
		id: string;
		name: string;
		firstName: string | null;
		lastName: string | null;
		email: string | null;
		address: {
			addressLine1: string | null;
			addressLine2: string | null;
			city: string | null;
			province: { code: string; name: string } | null;
			country: { code: string; name: string } | null;
			postalCode: string | null;
		} | null;
	};
	items: WaveInvoiceItem[];
	discounts: WaveInvoiceDiscount[];
	subtotal: { value: string; currency: { code: string; symbol: string } };
	taxTotal: { value: string; currency: { code: string; symbol: string } };
	discountTotal: { value: string; currency: { code: string; symbol: string } };
	total: { value: string; currency: { code: string; symbol: string } };
	amountDue: { value: string; currency: { code: string; symbol: string } };
	amountPaid: { value: string; currency: { code: string; symbol: string } };
	currency: { code: string; symbol: string; name: string };
	exchangeRate: number | null;
	createdAt: string;
	modifiedAt: string;
	lastSentAt: string | null;
	lastSentVia: string | null;
	lastViewedAt: string | null;
}

interface WaveResponse {
	data?: {
		business: {
			id: string;
			invoice: WaveInvoice | null;
		};
	};
	errors?: Array<{ message: string }>;
}

async function fetchWaveProducts(): Promise<WaveProduct[]> {
	try {
		const response = await fetch(WAVE_API_URL, {
			method: 'POST',
			headers: {
				'Content-Type': 'application/json',
				Authorization: `Bearer ${WAVE_ACCESS_TOKEN}`
			},
			body: JSON.stringify({
				query: GET_PRODUCTS_QUERY,
				variables: {
					businessId: PUBLIC_WAVE_BUSINESS_ID,
					pageSize: 500
				}
			})
		});

		const result = await response.json();
		if (result.errors) {
			console.error('Wave API errors (products):', result.errors);
			return [];
		}

		const edges = result.data?.business?.products?.edges ?? [];
		return edges
			.filter((edge: { node: WaveProduct | null }) => edge.node != null)
			.map((edge: { node: WaveProduct }) => ({
				id: edge.node.id,
				name: edge.node.name,
				description: edge.node.description,
				unitPrice: parseFloat(String(edge.node.unitPrice)),
				isArchived: edge.node.isArchived
			}));
	} catch (err) {
		console.error('Wave API fetch error (products):', err);
		return [];
	}
}

export const load: PageServerLoad = async ({ params }) => {
	const invoiceId = params.invoice;

	// Fetch invoice and products in parallel
	const [invoiceResponse, waveProducts] = await Promise.all([
		fetch(WAVE_API_URL, {
			method: 'POST',
			headers: {
				'Content-Type': 'application/json',
				Authorization: `Bearer ${WAVE_ACCESS_TOKEN}`
			},
			body: JSON.stringify({
				query: GET_INVOICE_QUERY,
				variables: {
					businessId: PUBLIC_WAVE_BUSINESS_ID,
					invoiceId
				}
			})
		}).catch((err) => {
			console.error('Wave API fetch error:', err);
			throw error(500, err instanceof Error ? err.message : 'Failed to fetch invoice');
		}),
		fetchWaveProducts()
	]);

	const result: WaveResponse = await invoiceResponse.json();

	if (result.errors) {
		console.error('Wave API errors:', result.errors);
		throw error(500, result.errors[0]?.message ?? 'Failed to fetch invoice');
	}

	const invoice = result.data?.business?.invoice;

	if (!invoice) {
		throw error(404, 'Invoice not found');
	}

	return {
		invoice,
		waveProducts
	};
};

export const actions: Actions = {
	sendWaveInvoice: async ({ request }) => {
		const formData = await request.formData();
		const invoiceId = formData.get('invoiceId') as string;
		const customerEmail = formData.get('customerEmail') as string;

		if (!invoiceId) {
			return fail(400, { error: 'Missing invoice ID' });
		}

		if (!customerEmail) {
			return fail(400, { error: 'Customer email is required to send invoice' });
		}

		const result = await sendWaveInvoice(invoiceId, [customerEmail]);

		if (!result.success) {
			return fail(400, { error: result.error || 'Failed to send Wave invoice' });
		}

		return { success: true };
	},

	approveWaveInvoice: async ({ request }) => {
		const formData = await request.formData();
		const invoiceId = formData.get('invoiceId') as string;

		if (!invoiceId) {
			return fail(400, { error: 'Missing invoice ID' });
		}

		const result = await approveWaveInvoice(invoiceId);

		if (!result.success) {
			return fail(400, { error: result.error || 'Failed to approve Wave invoice' });
		}

		return { success: true };
	},

	updateWaveInvoice: async ({ request }) => {
		const formData = await request.formData();
		const invoiceId = formData.get('invoiceId') as string;
		const invoiceDate = formData.get('invoiceDate') as string;
		const dueDate = formData.get('dueDate') as string;
		const memo = formData.get('memo') as string | null;
		const footer = formData.get('footer') as string | null;
		const itemsJson = formData.get('items') as string;
		const discountJson = formData.get('discount') as string | null;

		if (!invoiceId || !itemsJson) {
			return fail(400, { error: 'Missing required fields' });
		}

		let items;
		try {
			items = JSON.parse(itemsJson);
		} catch {
			return fail(400, { error: 'Invalid items data' });
		}

		// Parse discount if provided
		let discounts;
		if (discountJson) {
			try {
				const discount = JSON.parse(discountJson);
				if (discount && discount.value > 0) {
					discounts = [
						{
							discountType: discount.type as 'PERCENTAGE' | 'FIXED',
							name: discount.name || 'Discount',
							...(discount.type === 'PERCENTAGE'
								? { percentage: discount.value.toString() }
								: { amount: discount.value.toString() })
						}
					];
				}
			} catch {
				// Ignore invalid discount data
			}
		}

		const result = await updateWaveInvoice({
			id: invoiceId,
			invoiceDate,
			dueDate,
			items,
			discounts,
			memo: memo || undefined,
			footer: footer || undefined
		});

		if (!result.success) {
			return fail(400, { error: result.error || 'Failed to update Wave invoice' });
		}

		return { success: true };
	},

	deleteWaveInvoice: async ({ request }) => {
		const formData = await request.formData();
		const invoiceId = formData.get('invoiceId') as string;

		if (!invoiceId) {
			return fail(400, { error: 'Missing invoice ID' });
		}

		const result = await deleteWaveInvoice(invoiceId);

		if (!result.success) {
			return fail(400, { error: result.error || 'Failed to delete Wave invoice' });
		}

		return { success: true, deleted: true };
	}
};
