import {Mapping, AddMarkStep, RemoveMarkStep} from "prosemirror-transform"

import {deactivateAllSelectedChanges} from "../state_plugins"

import {deleteNode} from "./delete"

export const accept = function(type, pos, view) {
    const tr = view.state.tr.setMeta('track', true), map = new Mapping()
    let reachedEnd = false
    const trackMark = view.state.doc.nodeAt(pos).marks.find(mark => mark.type.name===type)
    view.state.doc.nodesBetween(pos, view.state.doc.firstChild.nodeSize, (node, nodePos) => {
        if (nodePos < pos) {
            return true
        }
        if (reachedEnd) {
            return false
        }
        if (!node.isInline) {
            reachedEnd = true
        } else if (!trackMark.isInSet(node.marks)) {
            reachedEnd = true
            return false
        }

        if (type==='deletion') {
            deleteNode(tr, node, nodePos, map, true)
        } else if (type==='insertion') {
            if (node.attrs.track) {
                const track = node.attrs.track.filter(track => track.type !== 'insertion')
                if (node.attrs.track.length === track) {
                    return true
                }
                tr.setNodeMarkup(map.map(nodePos), null, Object.assign({}, node.attrs, {track}), node.marks)
                // Special case: first paragraph in list item by same user -- will also be accepted.
                if (node.type.name === 'list_item' && node.child(0) && node.child(0).type.name === 'paragraph') {
                    reachedEnd = false
                }
            } else {
                tr.step(
                    new AddMarkStep(
                        map.map(nodePos),
                        map.map(nodePos+node.nodeSize),
                        view.state.schema.marks.insertion.create(Object.assign({}, trackMark.attrs, {approved: true}))
                    )
                )
            }
        } else if (type==='format_change') {
            tr.step(
                new RemoveMarkStep(
                    map.map(nodePos),
                    map.map(nodePos+node.nodeSize),
                    trackMark
                )
            )
        } else if (type==='block_change') {
            const track = node.attrs.track.filter(track => track.type !== 'block_change')
            tr.setNodeMarkup(map.map(nodePos), null, Object.assign({}, node.attrs, {track}), node.marks)
        }
        return true
    })

    deactivateAllSelectedChanges(tr)

    if (tr.steps.length) {
        view.dispatch(tr)
    }
}
