import { useWindowSize } from '@vueuse/core'
import { computed } from 'vue'
import { viewports } from '@/libs/theme'

/**
 * Mosaic Layout Generator
 * Creates a space-filling layout by recursively subdividing areas
 */

const { width: wWidth, height: wHeight } = useWindowSize()

export const useMosaicLayout = () => {
    const dvw = (pixels) => (pixels / viewports.desktop.width) * wWidth.value
    const dvh = (pixels) => (pixels / viewports.desktop.height) * wHeight.value

    /**
     * Generate a space-filling mosaic layout
     * @param {Object} options Layout configuration
     * @param {number} options.width Viewport width
     * @param {number} options.height Viewport height
     * @param {number} options.minCellWidth Minimum cell width
     * @param {number} options.maxCellWidth Maximum cell width
     * @param {number} options.minCellHeight Minimum cell height
     * @param {number} options.maxCellHeight Maximum cell height
     * @param {number} options.targetCells Target number of cells to create (if specified, overrides subdivisionProbability)
     * @param {number} options.subdivisionProbability Probability of subdivision (0-1) - used when targetCells is not specified
     * @returns {ComputedRef} Computed ref of array of cell objects with x, y, width, height, id
     */
    const generateLayout = (options = {}) => {
        return computed(() => {
            const {
                width = wWidth.value,
                height = wHeight.value,
                minCellWidth = dvw(150),
                minCellHeight = dvh(150),
                targetCells = 5,
            } = typeof options === 'function' ? options() : options

            return generateLayoutWithCellCount(
                width,
                height,
                targetCells,
                minCellWidth,
                minCellHeight,
            )
        })
    }

    /**
     * Generate layout with a specific number of cells
     * @param {number} width Viewport width
     * @param {number} height Viewport height
     * @param {number} targetCells Target number of cells
     * @param {number} minCellWidth Minimum cell width
     * @param {number} minCellHeight Minimum cell height
     * @returns {Array} Array of cell objects
     */
    const generateLayoutWithCellCount = (
        width,
        height,
        targetCells,
        minCellWidth,
        minCellHeight,
    ) => {
        const areas = [{ x: 0, y: 0, width, height, id: 0 }]
        let cellId = 0

        // Keep subdividing until we have enough cells or can't subdivide further
        while (areas.length < targetCells) {
            // Find areas that can be subdivided
            const subdividableAreas = areas.filter((area) => {
                const canSubdivideWidth = area.width >= minCellWidth * 2
                const canSubdivideHeight = area.height >= minCellHeight * 2
                return canSubdivideWidth || canSubdivideHeight
            })

            if (subdividableAreas.length === 0) {
                // No more areas can be subdivided, break
                console.log(
                    `Stopped at ${areas.length} cells - no more areas can be subdivided`,
                )
                break
            }

            // Choose area to subdivide - prefer larger areas
            subdividableAreas.sort(
                (a, b) => b.width * b.height - a.width * a.height,
            )
            const areaToSplit = subdividableAreas[0]
            const areaIndex = areas.indexOf(areaToSplit)

            // Remove the area we're about to split
            areas.splice(areaIndex, 1)

            // Determine split direction
            const canSubdivideWidth = areaToSplit.width >= minCellWidth * 2
            const canSubdivideHeight = areaToSplit.height >= minCellHeight * 2

            let splitVertical = true
            if (canSubdivideWidth && canSubdivideHeight) {
                const aspectRatio = areaToSplit.width / areaToSplit.height
                splitVertical = aspectRatio > 1
            } else {
                splitVertical = canSubdivideWidth
            }

            // Split the area
            if (splitVertical) {
                const splitRatio = 0.3 + Math.random() * 0.4 // Between 30% and 70%
                const leftWidth = Math.max(
                    minCellWidth,
                    Math.min(
                        areaToSplit.width - minCellWidth,
                        areaToSplit.width * splitRatio,
                    ),
                )
                const rightWidth = areaToSplit.width - leftWidth

                areas.push({
                    x: areaToSplit.x,
                    y: areaToSplit.y,
                    width: leftWidth,
                    height: areaToSplit.height,
                    id: cellId++,
                })
                areas.push({
                    x: areaToSplit.x + leftWidth,
                    y: areaToSplit.y,
                    width: rightWidth,
                    height: areaToSplit.height,
                    id: cellId++,
                })
            } else {
                const splitRatio = 0.3 + Math.random() * 0.4 // Between 30% and 70%
                const topHeight = Math.max(
                    minCellHeight,
                    Math.min(
                        areaToSplit.height - minCellHeight,
                        areaToSplit.height * splitRatio,
                    ),
                )
                const bottomHeight = areaToSplit.height - topHeight

                areas.push({
                    x: areaToSplit.x,
                    y: areaToSplit.y,
                    width: areaToSplit.width,
                    height: topHeight,
                    id: cellId++,
                })
                areas.push({
                    x: areaToSplit.x,
                    y: areaToSplit.y + topHeight,
                    width: areaToSplit.width,
                    height: bottomHeight,
                    id: cellId++,
                })
            }
        }

        // Convert areas to cells, normalise to 0-1 so consumers can use vw/vh
        return areas.map((area) => ({
            id: area.id,
            x: area.x / width,
            y: area.y / height,
            width: area.width / width,
            height: area.height / height,
        }))
    }

    /**
     * Generate content for each cell in the layout
     * @param {Array} cells Array of cell objects
     * @param {Function} contentGenerator Function to generate content for each cell
     * @returns {Array} Cells with content attached
     */
    const populateCells = (cells, contentGenerator) => {
        return cells.map((cell) => ({
            ...cell,
            content: contentGenerator(cell),
        }))
    }

    return {
        generateLayout,
        populateCells,
    }
}
