import { Points } from './utils.js'
import { Capabilities } from './capabilities.js'

export class FrameContainer {
    constructor(element) {
        this.element = element
        this.delegate = new InteractionMapper(element, this, {
            mouseWheelElement: window,
        })
    }

    capture(event) {
        return true
    }

    findTarget(event, local, global) {
        let found = document.elementFromPoint(global.x, global.y)
        let iframe = found.querySelector('iframe')
        if (iframe) {
            let p = Points.fromPageToNode(found, global)
            let doc = iframe.contentWindow.document
            let target = doc.elementFromPoint(p.x, p.y)
            if (target != null) {
                console.log('iframe element', target)
                return new FrameTarget(iframe, target)
            }
        }
        return null
    }
}

export class FrameTarget {
    constructor(frame, target, debug = false) {
        this.frame = frame
        this.target = target
        this.debug = debug
    }

    capture(event) {
        return true
    }

    simulateMouseEvent(type, point) {
        let p = Points.fromPageToNode(this.frame, point)
        let event = new MouseEvent(type, {
            view: this.frame.contentWindow,
            bubbles: true,
            cancelable: true,
            clientX: p.x,
            clientY: p.y,
        })
        this.target.dispatchEvent(event)
    }

    createTouchList(pointMap) {
        let touches = []
        let doc = this.frame.contentWindow.document
        for (let key of pointMap.keys()) {
            let point = pointMap.get(key)
            let p = Points.fromPageToNode(this.frame, point)
            let touchTarget = doc.elementFromPoint(p.x, p.y)
            let touch = new Touch(undefined, touchTarget, key, p.x, p.y, p.x, p.y)
            touches.push(touch)
        }
        return new TouchList(...touches)
    }

    simulateTouchEventChrome(type, point, pointMap) {
        let doc = this.frame.contentWindow.document
        let p = Points.fromPageToNode(this.frame, point)
        let touchTarget = doc.elementFromPoint(p.x, p.y)
        const touchObj = new Touch({
            identifier: Date.now(),
            target: touchTarget,
            clientX: p.x,
            clientY: p.y,
            pageX: p.x,
            pageY: p.y,
            radiusX: 2.5,
            radiusY: 2.5,
            rotationAngle: 10,
            force: 0.5,
        })

        const touchEvent = new TouchEvent(type, {
            cancelable: true,
            bubbles: true,
            touches: [touchObj],
            targetTouches: [touchObj],
            changedTouches: [touchObj],
            shiftKey: false,
        })
        if (this.debug) console.log('simulateTouchEventChrome', touchEvent)
        this.target.dispatchEvent(touchEvent)
    }

    simulateTouchEventSafari(type, point, pointMap, touchEventKey = 'targetTouches') {
        let p = Points.fromPageToNode(this.frame, point)
        let data = {
            view: this.frame.contentWindow,
            bubbles: true,
            cancelable: true,
            clientX: p.x,
            clientY: p.y,
        }
        data[touchEventKey] = this.createTouchList(pointMap)
        let event = new TouchEvent(type, data)
        if (this.debug) console.log('simulateTouchEventChrome', touchEvent)
        this.target.dispatchEvent(event)
    }

    simulateTouchEvent(type, point, pointMap, touchEventKey = 'targetTouches') {
        if (Capabilities.isSafari) {
            this.simulateTouchEventSafari(type, point, pointMap, touchEventKey)
        } else {
            this.simulateTouchEventChrome(type, point, pointMap)
        }
    }

    isMouseLikeEvent(event) {
        return event.type.startsWith('mouse') || event.type.startsWith('pointer')
    }

    onStart(event, interaction) {
        if (this.debug) console.log('onStart', this.frame.parentNode)
        for (let [key, point] of interaction.current.entries()) {
            if (this.isMouseLikeEvent(event)) {
                this.simulateMouseEvent('mousedown', point)
            } else {
                this.simulateTouchEvent('touchstart', point, interaction.current)
                return
            }
        }
    }

    onMove(event, interaction) {
        if (this.debug) console.log('onMove')
        for (let [key, point] of interaction.current.entries()) {
            if (this.isMouseLikeEvent(event)) {
                this.simulateMouseEvent('mousemove', point)
            } else {
                this.simulateTouchEvent('touchmove', point, interaction.current)
                return
            }
        }
    }

    onEnd(event, interaction) {
        if (this.debug) console.log('onEnd')
        for (let [key, point] of interaction.current.entries()) {
            if (this.isMouseLikeEvent(event)) {
                this.simulateMouseEvent('mouseend', point)
            } else {
                this.simulateTouchEvent('touchend', point, interaction.ended, 'changedTouches')
                return
            }
        }
    }
}