import { defineStore } from "pinia";

export const usePaginationStore = defineStore("pagination", {
	state: () => ({
		// Store pagination state by table/component name
		tablePagination: {
			clients: {
				first: 0, // Starting index for current page
				page: 0, // Current page number (0-based)
				rows: 10, // Items per page
				totalRecords: 0, // Total number of records available
				sortField: null, // Current sort field
				sortOrder: null, // Sort direction (1 for asc, -1 for desc)
			},
			jobs: {
				first: 0,
				page: 0,
				rows: 10,
				totalRecords: 0,
				sortField: null,
				sortOrder: null,
			},
			estimates: {
				first: 0,
				page: 0,
				rows: 10,
				totalRecords: 0,
				sortField: null,
				sortOrder: null,
			},
			timesheets: {
				first: 0,
				page: 0,
				rows: 10,
				totalRecords: 0,
				sortField: null,
				sortOrder: null,
			},
			warranties: {
				first: 0,
				page: 0,
				rows: 10,
				totalRecords: 0,
				sortField: null,
				sortOrder: null,
			},
			routes: {
				first: 0,
				page: 0,
				rows: 10,
				totalRecords: 0,
				sortField: null,
				sortOrder: null,
			},
		},

		// Page data cache: tableName -> { pageKey -> { data, timestamp, filterHash } }
		pageCache: {},

		// Cache configuration
		cacheTimeout: 5 * 60 * 1000, // 5 minutes in milliseconds
		maxCacheSize: 50, // Maximum number of cached pages per table
	}),

	getters: {
		// Get pagination state for a specific table
		getTablePagination: (state) => (tableName) => {
			return (
				state.tablePagination[tableName] || {
					first: 0,
					page: 0,
					rows: 10,
					totalRecords: 0,
					sortField: null,
					sortOrder: null,
				}
			);
		},

		// Calculate total pages for a table
		getTotalPages: (state) => (tableName) => {
			const pagination = state.tablePagination[tableName];
			if (!pagination || pagination.totalRecords === 0) return 0;
			return Math.ceil(pagination.totalRecords / pagination.rows);
		},

		// Check if there's a next page
		hasNextPage: (state) => (tableName) => {
			const pagination = state.tablePagination[tableName];
			if (!pagination) return false;
			return pagination.page + 1 < Math.ceil(pagination.totalRecords / pagination.rows);
		},

		// Check if there's a previous page
		hasPreviousPage: (state) => (tableName) => {
			const pagination = state.tablePagination[tableName];
			if (!pagination) return false;
			return pagination.page > 0;
		},

		// Get current page info for display
		getPageInfo: (state) => (tableName) => {
			const pagination = state.tablePagination[tableName];
			if (!pagination) return { start: 0, end: 0, total: 0 };

			const start = pagination.first + 1;
			const end = Math.min(pagination.first + pagination.rows, pagination.totalRecords);
			const total = pagination.totalRecords;

			return { start, end, total };
		},
	},

	actions: {
		// Initialize pagination for a table if it doesn't exist
		initializeTablePagination(tableName, options = {}) {
			if (!this.tablePagination[tableName]) {
				this.tablePagination[tableName] = {
					first: 0,
					page: 0,
					rows: options.rows || 10,
					totalRecords: options.totalRecords || 0,
					sortField: options.sortField || null,
					sortOrder: options.sortOrder || null,
				};
			}
		},

		// Update pagination state for a table
		updateTablePagination(tableName, paginationData) {
			if (!this.tablePagination[tableName]) {
				this.initializeTablePagination(tableName);
			}

			// Update provided fields
			Object.keys(paginationData).forEach((key) => {
				if (paginationData[key] !== undefined) {
					this.tablePagination[tableName][key] = paginationData[key];
				}
			});

			// Ensure consistency between page and first
			if (paginationData.page !== undefined) {
				this.tablePagination[tableName].first =
					paginationData.page * this.tablePagination[tableName].rows;
			} else if (paginationData.first !== undefined) {
				this.tablePagination[tableName].page = Math.floor(
					paginationData.first / this.tablePagination[tableName].rows,
				);
			}
		},

		// Set current page
		setPage(tableName, page) {
			this.updateTablePagination(tableName, {
				page: page,
				first: page * this.getTablePagination(tableName).rows,
			});
		},

		// Set rows per page
		setRowsPerPage(tableName, rows) {
			const currentPagination = this.getTablePagination(tableName);
			const newPage = Math.floor(currentPagination.first / rows);

			this.updateTablePagination(tableName, {
				rows: rows,
				page: newPage,
				first: newPage * rows,
			});
		},

		// Set total records (usually after API response)
		setTotalRecords(tableName, totalRecords) {
			this.updateTablePagination(tableName, {
				totalRecords: totalRecords,
			});

			// Ensure current page is valid
			const currentPagination = this.getTablePagination(tableName);
			const maxPages = Math.ceil(totalRecords / currentPagination.rows);
			if (currentPagination.page >= maxPages && maxPages > 0) {
				this.setPage(tableName, maxPages - 1);
			}
		},

		// Set sort information
		setSorting(tableName, sortField, sortOrder) {
			this.updateTablePagination(tableName, {
				sortField: sortField,
				sortOrder: sortOrder,
			});
		},

		// Go to next page
		nextPage(tableName) {
			const pagination = this.getTablePagination(tableName);
			if (this.hasNextPage(tableName)) {
				this.setPage(tableName, pagination.page + 1);
			}
		},

		// Go to previous page
		previousPage(tableName) {
			const pagination = this.getTablePagination(tableName);
			if (this.hasPreviousPage(tableName)) {
				this.setPage(tableName, pagination.page - 1);
			}
		},

		// Go to first page
		firstPage(tableName) {
			this.setPage(tableName, 0);
		},

		// Go to last page
		lastPage(tableName) {
			const totalPages = this.getTotalPages(tableName);
			if (totalPages > 0) {
				this.setPage(tableName, totalPages - 1);
			}
		},

		// Reset pagination to first page (useful when filters change)
		resetToFirstPage(tableName) {
			this.updateTablePagination(tableName, {
				page: 0,
				first: 0,
			});
		},

		// Clear all pagination data for a table
		clearTablePagination(tableName) {
			if (this.tablePagination[tableName]) {
				this.tablePagination[tableName] = {
					first: 0,
					page: 0,
					rows: 10,
					totalRecords: 0,
					sortField: null,
					sortOrder: null,
				};
			}
		},

		// Get formatted pagination parameters for API calls
		getPaginationParams(tableName) {
			const pagination = this.getTablePagination(tableName);
			return {
				page: pagination.page,
				pageSize: pagination.rows,
				offset: pagination.first,
				limit: pagination.rows,
				sortField: pagination.sortField,
				sortOrder: pagination.sortOrder,
			};
		},

		// Handle PrimeVue lazy pagination event
		handleLazyLoad(tableName, event) {
			console.log("Pagination lazy load event:", event);

			const page = Math.floor(event.first / event.rows);

			this.updateTablePagination(tableName, {
				first: event.first,
				page: page,
				rows: event.rows,
				sortField: event.sortField,
				sortOrder: event.sortOrder,
			});

			return this.getPaginationParams(tableName);
		},

		// Cache management methods
		generateCacheKey(page, pageSize, sortField, sortOrder, filters) {
			const filterHash = this.hashFilters(filters);
			return `${page}-${pageSize}-${sortField || "none"}-${sortOrder || 0}-${filterHash}`;
		},

		hashFilters(filters) {
			if (!filters || Object.keys(filters).length === 0) return "no-filters";

			const sortedKeys = Object.keys(filters).sort();
			const filterString = sortedKeys
				.map((key) => {
					const filter = filters[key];
					const value = filter?.value || "";
					const matchMode = filter?.matchMode || "";
					return `${key}:${value}:${matchMode}`;
				})
				.join("|");

			// Simple hash function
			let hash = 0;
			for (let i = 0; i < filterString.length; i++) {
				const char = filterString.charCodeAt(i);
				hash = (hash << 5) - hash + char;
				hash = hash & hash; // Convert to 32bit integer
			}
			return Math.abs(hash).toString(36);
		},

		getCachedPage(tableName, page, pageSize, sortField, sortOrder, filters) {
			if (!this.pageCache[tableName]) return null;

			const cacheKey = this.generateCacheKey(page, pageSize, sortField, sortOrder, filters);
			const cachedEntry = this.pageCache[tableName][cacheKey];

			if (!cachedEntry) return null;

			// Check if cache entry is still valid (not expired)
			const now = Date.now();
			if (now - cachedEntry.timestamp > this.cacheTimeout) {
				// Cache expired, remove it
				delete this.pageCache[tableName][cacheKey];
				return null;
			}

			console.log(`Cache HIT for ${tableName} page ${page + 1}`);
			return cachedEntry.data;
		},

		setCachedPage(tableName, page, pageSize, sortField, sortOrder, filters, data) {
			if (!this.pageCache[tableName]) {
				this.pageCache[tableName] = {};
			}

			const cacheKey = this.generateCacheKey(page, pageSize, sortField, sortOrder, filters);

			// Clean up old cache entries if we're at the limit
			const cacheKeys = Object.keys(this.pageCache[tableName]);
			if (cacheKeys.length >= this.maxCacheSize) {
				// Remove oldest entries (simple FIFO approach)
				const sortedEntries = cacheKeys
					.map((key) => ({ key, timestamp: this.pageCache[tableName][key].timestamp }))
					.sort((a, b) => a.timestamp - b.timestamp);

				// Remove oldest 25% of entries
				const toRemove = Math.floor(this.maxCacheSize * 0.25);
				for (let i = 0; i < toRemove; i++) {
					delete this.pageCache[tableName][sortedEntries[i].key];
				}
			}

			this.pageCache[tableName][cacheKey] = {
				data: JSON.parse(JSON.stringify(data)), // Deep clone to prevent mutations
				timestamp: Date.now(),
			};

			console.log(
				`Cache SET for ${tableName} page ${page + 1}, total cached pages: ${Object.keys(this.pageCache[tableName]).length}`,
			);
		},

		clearTableCache(tableName) {
			if (this.pageCache[tableName]) {
				delete this.pageCache[tableName];
				console.log(`Cache cleared for ${tableName}`);
			}
		},

		clearExpiredCache() {
			const now = Date.now();
			Object.keys(this.pageCache).forEach((tableName) => {
				Object.keys(this.pageCache[tableName]).forEach((cacheKey) => {
					if (now - this.pageCache[tableName][cacheKey].timestamp > this.cacheTimeout) {
						delete this.pageCache[tableName][cacheKey];
					}
				});

				// If no cache entries left for this table, remove the table key
				if (Object.keys(this.pageCache[tableName]).length === 0) {
					delete this.pageCache[tableName];
				}
			});
		},

		getCacheStats(tableName) {
			if (!this.pageCache[tableName]) {
				return { totalPages: 0, totalSize: 0 };
			}

			const pages = Object.keys(this.pageCache[tableName]);
			const totalSize = pages.reduce((size, key) => {
				return size + JSON.stringify(this.pageCache[tableName][key]).length;
			}, 0);

			return {
				totalPages: pages.length,
				totalSize: Math.round(totalSize / 1024) + " KB",
			};
		},
	},
});
