export default function keyValueFormComponent({ state }) {
    return {
        state,

        rows: [],

        shouldUpdateRows: true,

        init: function () {
            this.updateRows()

            if (this.rows.length <= 0) {
                this.rows.push({ key: '', value: '' })
            } else {
                this.updateState()
            }

            this.$watch('state', (state, oldState) => {
                const getLength = (value) => {
                    if (value === null) {
                        return 0
                    }

                    if (Array.isArray(value)) {
                        return value.length
                    }

                    if (typeof value !== 'object') {
                        return 0
                    }

                    return Object.keys(value).length
                }

                if (getLength(state) === 0 && getLength(oldState) === 0) {
                    return
                }

                this.updateRows()
            })
        },

        addRow: function () {
            this.rows.push({ key: '', value: '' })

            this.updateState()
        },

        deleteRow: function (index) {
            this.rows.splice(index, 1)

            if (this.rows.length <= 0) {
                this.addRow()
            }

            this.updateState()
        },

        reorderRows: function (event) {
            const rows = Alpine.raw(this.rows)

            this.rows = []

            const reorderedRow = rows.splice(event.oldIndex, 1)[0]
            rows.splice(event.newIndex, 0, reorderedRow)

            this.$nextTick(() => {
                this.rows = rows

                this.updateState()
            })
        },

        updateRows: function () {
            if (!this.shouldUpdateRows) {
                this.shouldUpdateRows = true

                return
            }

            let rows = []

            for (let [key, value] of Object.entries(this.state ?? {})) {
                rows.push({
                    key,
                    value,
                })
            }

            this.rows = rows
        },

        updateState: function () {
            let state = {}

            this.rows.forEach((row) => {
                if (row.key === '' || row.key === null) {
                    return
                }

                state[row.key] = row.value
            })

            // This is a hack to prevent the component from updating rows again
            // after a state update, which would otherwise be done by the `state`
            // watcher. If rows are updated again, duplicate keys are removed.
            //
            // https://github.com/filamentphp/filament/issues/1107
            this.shouldUpdateRows = false

            this.state = state
        },
    }
}
