import type { Ref } from 'vue'
import type { ColumnConfig, Row } from '../types'
import { computed, ref, watch, onUnmounted } from 'vue'

export function useSpreadsheetColumns(
	localRows: Ref<Row[]>,
	getColumnConfig: () => ColumnConfig[] | undefined,
) {
	const visibleColumns = ref<string[]>([])
	const columnWidths = ref<Map<string, number>>(new Map())

	const isResizing = ref(false)
	const resizingColumn = ref<string | null>(null)
	const startX = ref(0)
	const startWidth = ref(0)

	const columns = computed<ColumnConfig[]>(() => {
		const dataKeys = localRows.value.length
			? new Set(localRows.value.flatMap(row => Object.keys(row)))
			: new Set<string>()

		const config = getColumnConfig()
		const configMap = new Map((config || []).map(c => [c.key, c]))
		const allKeys = new Set([...dataKeys, ...(config?.map(c => c.key) || [])])

		return Array.from(allKeys).map((key) => {
			const col = configMap.get(key)
			return {
				key,
				label: col?.label ?? key,
				locked: col?.locked ?? false,
				sortable: col?.sortable ?? true,
				format: col?.format ?? 'text',
				width: col?.width,
				fixed: col?.fixed ?? false,
				hidden: col?.hidden ?? false,
				defaultValue: col?.defaultValue,
			}
		})
	})

	const fixedColumns = computed(() => columns.value.filter(col => col.fixed && !col.hidden && visibleColumns.value.includes(col.key))
	)

	const scrollableColumns = computed(() => columns.value.filter(col => !col.fixed && !col.hidden && visibleColumns.value.includes(col.key))
	)

	const columnOptions = computed(() => columns.value.filter(col => !col.hidden))

	watch(columns, (newColumns) => {
		if (newColumns.length > 0 && visibleColumns.value.length === 0) {
			visibleColumns.value = newColumns.filter(col => !col.hidden).map(col => col.key)
		}
	})

	function isCellEditable(columnKey: string): boolean {
		return !(columns.value.find(col => col.key === columnKey)?.locked ?? false)
	}

	function createEmptyRow(): Row {
		const row: Row = {}
		columns.value.forEach((col) => {
			row[col.key] = col.defaultValue !== undefined
				? col.defaultValue
				: col.format === 'boolean' ? false : ''
		})
		return row
	}

	function handleResizeMove(e: MouseEvent) {
		if (!isResizing.value || !resizingColumn.value) { return }
		e.preventDefault()
		const newWidth = Math.max(80, startWidth.value + (e.pageX - startX.value))
		columnWidths.value.set(resizingColumn.value, newWidth)
	}

	function handleResizeEnd() {
		isResizing.value = false
		resizingColumn.value = null
		document.removeEventListener('mousemove', handleResizeMove)
		document.removeEventListener('mouseup', handleResizeEnd)
	}

	function handleResizeStart(e: MouseEvent, columnKey: string) {
		isResizing.value = true
		resizingColumn.value = columnKey
		startX.value = e.pageX
		const th = (e.target as HTMLElement).closest('th')
		startWidth.value = columnWidths.value.get(columnKey) ?? (th?.getBoundingClientRect().width ?? 0)
		document.addEventListener('mousemove', handleResizeMove)
		document.addEventListener('mouseup', handleResizeEnd)
	}

	onUnmounted(() => {
		document.removeEventListener('mousemove', handleResizeMove)
		document.removeEventListener('mouseup', handleResizeEnd)
	})

	return {
		columns,
		fixedColumns,
		scrollableColumns,
		columnOptions,
		visibleColumns,
		columnWidths,
		isCellEditable,
		createEmptyRow,
		handleResizeStart,
	}
}
