import { WAVE_ACCESS_TOKEN } from '$env/static/private';
import { PUBLIC_WAVE_BUSINESS_ID } from '$env/static/public';
import { fail } from '@sveltejs/kit';
import {
	createWaveProduct,
	updateWaveProduct,
	archiveWaveProduct,
	createWaveCustomer,
	updateWaveCustomer,
	deleteWaveCustomer
} from '$lib/graphql/wave/mutations';
import type { PageServerLoad, Actions } from './$types';

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

const GET_ALL_DATA_QUERY = `
	query GetAllWaveData($businessId: ID!, $invoicePage: Int, $invoicePageSize: Int, $productPageSize: Int, $customerPageSize: Int) {
		business(id: $businessId) {
			id
			name
			accounts(types: [INCOME], isArchived: false) {
				edges {
					node {
						id
						name
						subtype {
							value
						}
					}
				}
			}
			invoices(page: $invoicePage, pageSize: $invoicePageSize, sort: [INVOICE_DATE_DESC]) {
				edges {
					node {
						id
						invoiceNumber
						invoiceDate
						dueDate
						status
						title
						customer {
							id
							name
							email
						}
						amountDue {
							value
							currency {
								code
								symbol
							}
						}
						amountPaid {
							value
							currency {
								code
								symbol
							}
						}
						total {
							value
							currency {
								code
								symbol
							}
						}
						lastSentAt
						lastViewedAt
					}
				}
				pageInfo {
					currentPage
					totalPages
					totalCount
				}
			}
			products(pageSize: $productPageSize, sort: [NAME_ASC], isArchived: false) {
				edges {
					node {
						id
						name
						description
						unitPrice
						isSold
						isBought
						isArchived
						incomeAccount {
							id
							name
						}
						expenseAccount {
							id
							name
						}
						defaultSalesTaxes {
							id
							name
							abbreviation
						}
						createdAt
						modifiedAt
					}
				}
				pageInfo {
					currentPage
					totalPages
					totalCount
				}
			}
			archivedProducts: products(pageSize: $productPageSize, sort: [NAME_ASC], isArchived: true) {
				edges {
					node {
						id
						name
						description
						unitPrice
						isSold
						isBought
						isArchived
						incomeAccount {
							id
							name
						}
						expenseAccount {
							id
							name
						}
						defaultSalesTaxes {
							id
							name
							abbreviation
						}
						createdAt
						modifiedAt
					}
				}
			}
			customers(pageSize: $customerPageSize, sort: [NAME_ASC]) {
				edges {
					node {
						id
						name
						firstName
						lastName
						email
						phone
						mobile
						currency {
							code
							symbol
						}
						address {
							addressLine1
							addressLine2
							city
							province {
								code
								name
							}
							country {
								code
								name
							}
							postalCode
						}
						internalNotes
						outstandingAmount {
							value
							currency {
								code
							}
						}
						overdueAmount {
							value
							currency {
								code
							}
						}
						createdAt
						modifiedAt
						isArchived
					}
				}
				pageInfo {
					currentPage
					totalPages
					totalCount
				}
			}
		}
	}
`;

interface WaveInvoice {
	id: string;
	invoiceNumber: string;
	invoiceDate: string;
	dueDate: string;
	status: string;
	title: string | null;
	customer: {
		id: string;
		name: string;
		email: string | null;
	};
	amountDue: {
		value: string;
		currency: {
			code: string;
			symbol: string;
		};
	};
	amountPaid: {
		value: string;
		currency: {
			code: string;
			symbol: string;
		};
	};
	total: {
		value: string;
		currency: {
			code: string;
			symbol: string;
		};
	};
	lastSentAt: string | null;
	lastViewedAt: string | null;
}

interface WaveProduct {
	id: string;
	name: string;
	description: string | null;
	unitPrice: string;
	isSold: boolean;
	isBought: boolean;
	isArchived: boolean;
	incomeAccount: { id: string; name: string } | null;
	expenseAccount: { id: string; name: string } | null;
	defaultSalesTaxes: Array<{ id: string; name: string; abbreviation: string }>;
	createdAt: string;
	modifiedAt: string;
}

interface WaveCustomer {
	id: string;
	name: string;
	firstName: string | null;
	lastName: string | null;
	email: string | null;
	phone: string | null;
	mobile: string | null;
	currency: { code: string; symbol: 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;
	internalNotes: string | null;
	outstandingAmount: { value: string; currency: { code: string } };
	overdueAmount: { value: string; currency: { code: string } };
	createdAt: string;
	modifiedAt: string;
	isArchived: boolean | null;
}

interface WaveAccount {
	id: string;
	name: string;
	subtype: { value: string };
}

interface WaveResponse {
	data?: {
		business: {
			id: string;
			name: string;
			accounts: {
				edges: Array<{ node: WaveAccount }>;
			};
			invoices: {
				edges: Array<{ node: WaveInvoice }>;
				pageInfo: {
					currentPage: number;
					totalPages: number;
					totalCount: number;
				};
			};
			products: {
				edges: Array<{ node: WaveProduct }>;
				pageInfo: {
					currentPage: number;
					totalPages: number;
					totalCount: number;
				};
			};
			archivedProducts: {
				edges: Array<{ node: WaveProduct }>;
			};
			customers: {
				edges: Array<{ node: WaveCustomer }>;
				pageInfo: {
					currentPage: number;
					totalPages: number;
					totalCount: number;
				};
			};
		};
	};
	errors?: Array<{ message: string }>;
}

export const load: PageServerLoad = async ({ url }) => {
	const page = parseInt(url.searchParams.get('page') ?? '1', 10);
	const pageSize = 20;

	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_ALL_DATA_QUERY,
				variables: {
					businessId: PUBLIC_WAVE_BUSINESS_ID,
					invoicePage: page,
					invoicePageSize: pageSize,
					productPageSize: 100,
					customerPageSize: 100
				}
			})
		});

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

		if (result.errors) {
			console.error('Wave API errors:', result.errors);
			return {
				invoices: [],
				products: [],
				archivedProducts: [],
				customers: [],
				incomeAccounts: [],
				invoicePageInfo: { currentPage: 1, totalPages: 1, totalCount: 0 },
				productPageInfo: { currentPage: 1, totalPages: 1, totalCount: 0 },
				customerPageInfo: { currentPage: 1, totalPages: 1, totalCount: 0 },
				businessName: null,
				error: result.errors[0]?.message ?? 'Unknown error'
			};
		}

		const business = result.data?.business;

		// Extract income accounts
		const incomeAccounts = business?.accounts.edges.map((e) => e.node) ?? [];

		// Transform products to have unitPrice as number
		const products = (business?.products.edges.map((e) => e.node) ?? []).map((p) => ({
			...p,
			unitPrice: parseFloat(p.unitPrice)
		}));

		// Transform archived products to have unitPrice as number
		const archivedProducts = (business?.archivedProducts.edges.map((e) => e.node) ?? []).map(
			(p) => ({
				...p,
				unitPrice: parseFloat(p.unitPrice)
			})
		);

		// Filter out archived customers
		const customers = (business?.customers.edges.map((e) => e.node) ?? []).filter(
			(c) => !c.isArchived
		);

		return {
			invoices: business?.invoices.edges.map((e) => e.node) ?? [],
			products,
			archivedProducts,
			customers,
			incomeAccounts,
			invoicePageInfo: business?.invoices.pageInfo ?? {
				currentPage: 1,
				totalPages: 1,
				totalCount: 0
			},
			productPageInfo: business?.products.pageInfo ?? {
				currentPage: 1,
				totalPages: 1,
				totalCount: 0
			},
			customerPageInfo: business?.customers.pageInfo ?? {
				currentPage: 1,
				totalPages: 1,
				totalCount: 0
			},
			businessName: business?.name ?? null,
			error: null
		};
	} catch (err) {
		console.error('Wave API fetch error:', err);
		return {
			invoices: [],
			products: [],
			archivedProducts: [],
			customers: [],
			incomeAccounts: [],
			invoicePageInfo: { currentPage: 1, totalPages: 1, totalCount: 0 },
			productPageInfo: { currentPage: 1, totalPages: 1, totalCount: 0 },
			customerPageInfo: { currentPage: 1, totalPages: 1, totalCount: 0 },
			businessName: null,
			error: err instanceof Error ? err.message : 'Failed to fetch data'
		};
	}
};

export const actions: Actions = {
	// Product actions
	createProduct: async ({ request }) => {
		const formData = await request.formData();
		const name = formData.get('name') as string;
		const unitPrice = parseFloat(formData.get('unitPrice') as string);
		const description = (formData.get('description') as string) || undefined;
		const incomeAccountId = (formData.get('incomeAccountId') as string) || undefined;

		if (!name || isNaN(unitPrice)) {
			return fail(400, { error: 'Name and unit price are required' });
		}

		const result = await createWaveProduct({ name, unitPrice, description, incomeAccountId });

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

		return { success: true, product: result.product };
	},

	updateProduct: async ({ request }) => {
		const formData = await request.formData();
		const id = formData.get('id') as string;
		const name = (formData.get('name') as string) || undefined;
		const unitPriceStr = formData.get('unitPrice') as string;
		const unitPrice = unitPriceStr ? parseFloat(unitPriceStr) : undefined;
		const description = (formData.get('description') as string) || undefined;
		const incomeAccountId = (formData.get('incomeAccountId') as string) || undefined;

		if (!id) {
			return fail(400, { error: 'Product ID is required' });
		}

		const result = await updateWaveProduct({ id, name, unitPrice, description, incomeAccountId });

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

		return { success: true, product: result.product };
	},

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

		if (!id) {
			return fail(400, { error: 'Product ID is required' });
		}

		const result = await archiveWaveProduct(id);

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

		return { success: true };
	},

	// Customer actions
	createCustomer: async ({ request }) => {
		const formData = await request.formData();
		const name = formData.get('name') as string;
		const firstName = (formData.get('firstName') as string) || undefined;
		const lastName = (formData.get('lastName') as string) || undefined;
		const email = (formData.get('email') as string) || undefined;
		const phone = (formData.get('phone') as string) || undefined;
		const internalNotes = (formData.get('internalNotes') as string) || undefined;

		// Address fields
		const addressLine1 = (formData.get('addressLine1') as string) || undefined;
		const addressLine2 = (formData.get('addressLine2') as string) || undefined;
		const city = (formData.get('city') as string) || undefined;
		const provinceCode = (formData.get('provinceCode') as string) || undefined;
		const countryCode = (formData.get('countryCode') as string) || undefined;
		const postalCode = (formData.get('postalCode') as string) || undefined;

		if (!name) {
			return fail(400, { error: 'Name is required' });
		}

		// Build address object if any address fields are provided
		const hasAddressFields =
			addressLine1 || addressLine2 || city || provinceCode || countryCode || postalCode;
		const address = hasAddressFields
			? { addressLine1, addressLine2, city, provinceCode, countryCode, postalCode }
			: undefined;

		const result = await createWaveCustomer({
			name,
			firstName,
			lastName,
			email,
			phone,
			address,
			internalNotes
		});

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

		return { success: true, customer: result.customer };
	},

	updateCustomer: async ({ request }) => {
		const formData = await request.formData();
		const id = formData.get('id') as string;
		const name = (formData.get('name') as string) || undefined;
		const firstName = (formData.get('firstName') as string) || undefined;
		const lastName = (formData.get('lastName') as string) || undefined;
		const email = (formData.get('email') as string) || undefined;
		const phone = (formData.get('phone') as string) || undefined;
		const internalNotes = (formData.get('internalNotes') as string) || undefined;

		// Address fields
		const addressLine1 = (formData.get('addressLine1') as string) || undefined;
		const addressLine2 = (formData.get('addressLine2') as string) || undefined;
		const city = (formData.get('city') as string) || undefined;
		const provinceCode = (formData.get('provinceCode') as string) || undefined;
		const countryCode = (formData.get('countryCode') as string) || undefined;
		const postalCode = (formData.get('postalCode') as string) || undefined;

		if (!id) {
			return fail(400, { error: 'Customer ID is required' });
		}

		// Build address object if any address fields are provided
		const hasAddressFields =
			addressLine1 || addressLine2 || city || provinceCode || countryCode || postalCode;
		const address = hasAddressFields
			? { addressLine1, addressLine2, city, provinceCode, countryCode, postalCode }
			: undefined;

		const result = await updateWaveCustomer({
			id,
			name,
			firstName,
			lastName,
			email,
			phone,
			address,
			internalNotes
		});

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

		return { success: true, customer: result.customer };
	},

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

		if (!id) {
			return fail(400, { error: 'Customer ID is required' });
		}

		const result = await deleteWaveCustomer(id);

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

		return { success: true };
	}
};
