import Point from '../Geometry/Point.js'
import Wall from '../Geometry/Wall.js'
import { mathUtil } from '../MathUtil.js'
import { floorplanService } from './FloorplanService.js'
import Constant from '../Constant'
import { listenLayer } from '../ListenLayer'
import { addWall } from '../Controls/AddWall'

export class WallService {
    constructor() {}

    getLine(wall) {
        const startPoint = floorplanService.getPoint(wall.start)
        const endPoint = floorplanService.getPoint(wall.end)
        const line = mathUtil.createLine1(startPoint, endPoint)
        return line
    }

    //point在wall所在的线上，只是不确定是否在线段上
    isContain(wall, point, minDis) {
        const startPoint = floorplanService.getPoint(wall.start)
        const endPoint = floorplanService.getPoint(wall.end)
        return mathUtil.isContainForSegment(point, startPoint, endPoint, minDis)
    }

    createWall(startId, endId, vectorId, floor) {
        let wall = new Wall(startId, endId, vectorId, floor)
        if (floor == null || typeof floor == 'undefined') {
            floor = floorplanService.currentFloor
        }
        floorplanService.addWall(wall, floor)
        this.setPointParent(wall.vectorId, startId, 'start', floor)
        this.setPointParent(wall.vectorId, endId, 'end', floor)
        return wall
    }

    createPoint(x, y, vectorId, floor) {
        let point = new Point(x, y, vectorId, floor)
        if (floor == null || typeof floor == 'undefined') {
            floor = floorplanService.currentFloor
        }
        floorplanService.addPoint(point, floor)
        return point
    }

    setPointParent(wallId, pointId, dir, floor) {
        let point = floorplanService.getPoint(pointId, floor)
        let wall = floorplanService.getWall(wallId, floor)
        point.setPointParent(wallId, dir)
        if (dir == 'start') {
            wall.start = pointId
        } else if (dir == 'end') {
            wall.end = pointId
        }
    }

    // wallId对应墙的两个端点。尽量不要改
    // dir表示:保留start还是保留end(对应端点的parent不用变)
    splitWall(wallId, pointId, dir) {
        const wall = floorplanService.getWall(wallId)
        const startPoint = floorplanService.getPoint(wall.start)
        const endPoint = floorplanService.getPoint(wall.end)
        const point = floorplanService.getPoint(pointId)
        if (mathUtil.getDistance(startPoint, point) < Constant.minAdsorb || mathUtil.getDistance(endPoint, point) < Constant.minAdsorb) {
            //console.error('splitWall********************************************1')
            //return null
        }

        // point1属于旧墙，point2属于新墙
        let newWall = null
        if (dir == 'start') {
            //floorplanService.deletePoint(wall.end, wallId)
            // 第一步先断开链接
            delete endPoint.parent[wallId]
            //新墙
            newWall = this.createWall(pointId, wall.end)

            //修改旧墙的end
            this.setPointParent(wallId, pointId, 'end')
            //旧墙的end的parent换成新墙
            endPoint.setPointParent(newWall.vectorId, dir)
        } else if (dir == 'end') {
            //floorplanService.deletePoint(wall.start, wallId)
            delete startPoint.parent[wallId]
            //新墙
            newWall = this.createWall(wall.start, pointId)

            //修改旧墙的end
            this.setPointParent(wallId, pointId, 'start')
            //旧墙的end的parent换成新墙
            startPoint.setPointParent(newWall.vectorId, dir)
        }

        return newWall.vectorId
    }

    // wallId的两个端点分别是pointId1,pointId2，获取这个wallId
    getWallId(pointId1, pointId2) {
        const point1 = floorplanService.getPoint(pointId1)
        const point2 = floorplanService.getPoint(pointId2)
        // 墙可能删除了。
        if (!point1 || !point2) {
            console.log('pointId1或者pointId2不存在')
            return null
        }
        if (pointId1 == pointId2) {
            console.log('给的是同一个point')
            return null
        }

        const parent1 = point1.parent
        const parent2 = point2.parent

        for (const key in parent1) {
            if (parent2.hasOwnProperty(key)) {
                return key
            }
        }

        return null
    }

    isWallLink(wallId1, wallId2) {
        let wall1 = floorplanService.getWall(wallId1)
        let wall2 = floorplanService.getWall(wallId2)

        if (wall1.start == wall2.start || wall1.start == wall2.end || wall1.end == wall2.start || wall1.end == wall2.end) {
            return true
        } else {
            return false
        }
    }

    // id1和id2不相交
    AngleForWall(id1, id2) {
        const wall1 = floorplanService.getWall(id1)
        const wall2 = floorplanService.getWall(id2)

        if (wall1 == null || wall2 == null || typeof wall1 === 'undefined' || typeof wall2 === 'undefined') {
            return null
        }

        const start1 = floorplanService.getPoint(wall1.start)
        const end1 = floorplanService.getPoint(wall1.end)

        const start2 = floorplanService.getPoint(wall2.start)
        const end2 = floorplanService.getPoint(wall2.end)

        const distance1 = mathUtil.getDistance(start1, start2)
        const distance2 = mathUtil.getDistance(start1, end2)

        const distance3 = mathUtil.getDistance(end1, start2)
        const distance4 = mathUtil.getDistance(end1, end2)

        const minDistance = Math.min(distance1, distance2, distance3, distance4)
        const join = mathUtil.getIntersectionPoint2(start1, end1, start2, end2)

        if (join == null) {
            return Math.PI
        }

        // start和start相交
        if (distance1 == minDistance) {
            end1.x += start2.x - start1.x
            end1.y += start2.y - start1.y
            return mathUtil.Angle(start2, end1, end2)
        } else if (distance2 == minDistance) {
            end1.x += end2.x - start1.x
            end1.y += end2.y - start1.y
            return mathUtil.Angle(end2, end1, start2)
        } else if (distance3 == minDistance) {
            start1.x += start2.x - end1.x
            start1.y += start2.y - end1.y
            return mathUtil.Angle(start2, start1, end2)
        } else if (distance4 == minDistance) {
            start1.x += end2.x - end1.x
            start1.y += end2.y - end1.y
            return mathUtil.Angle(end2, start1, start2)
        } else {
            console.error('AngleForWall**************************1')
            return null
        }
    }

    // 除了返回角度，还返回：id1对应的start,end和id2对应的另外一点组成的三角形，是顺时针还是逆时针
    AngleForWall2(id1, id2) {
        const wall1 = floorplanService.getWall(id1)
        const wall2 = floorplanService.getWall(id2)

        if (wall1 == null || wall2 == null || typeof wall1 === 'undefined' || typeof wall2 === 'undefined') {
            return null
        }

        const start1 = floorplanService.getPoint(wall1.start)
        const end1 = floorplanService.getPoint(wall1.end)

        const start2 = floorplanService.getPoint(wall2.start)
        const end2 = floorplanService.getPoint(wall2.end)

        let angle = null
        const points = []
        points.push(start1)
        points.push(end1)
        if (wall1.start == wall2.start) {
            angle = mathUtil.Angle(start1, end1, end2)
            points.push(end2)
        } else if (wall1.start == wall2.end) {
            angle = mathUtil.Angle(start1, end1, start2)
            points.push(start2)
        } else if (wall1.end == wall2.start) {
            angle = mathUtil.Angle(end1, start1, end2)
            points[0] = end1
            points[1] = start1
            points.push(end2)
        } else if (wall1.end == wall2.end) {
            angle = mathUtil.Angle(end1, start1, start2)
            points[0] = end1
            points[1] = start1
            points.push(start2)
        }

        if (angle == null) {
            return null
        } else {
            const flag = mathUtil.isClockwise(points)
            if (flag) {
                return {
                    angle: angle,
                    clockwise: 1,
                }
            } else {
                return {
                    angle: angle,
                    clockwise: 0,
                }
            }
        }
    }

    // id1的端点坐标不变
    AngleForWall3(id1, id2) {
        const wall1 = floorplanService.getWall(id1)
        const wall2 = floorplanService.getWall(id2)

        if (wall1 == null || wall2 == null || typeof wall1 === 'undefined' || typeof wall2 === 'undefined') {
            return null
        }

        const start1 = floorplanService.getPoint(wall1.start)
        const end1 = floorplanService.getPoint(wall1.end)

        const start2 = floorplanService.getPoint(wall2.start)
        const end2 = floorplanService.getPoint(wall2.end)

        const distance1 = mathUtil.getDistance(start1, start2)
        const distance2 = mathUtil.getDistance(start1, end2)

        const distance3 = mathUtil.getDistance(end1, start2)
        const distance4 = mathUtil.getDistance(end1, end2)

        const minDistance = Math.min(distance1, distance2, distance3, distance4)

        const _start1 = {}
        const _end1 = {}

        // start和start相交
        if (distance1 == minDistance) {
            _end1.x = end1.x + start2.x - start1.x
            _end1.y = end1.y + start2.y - start1.y
            return mathUtil.Angle(start2, _end1, end2)
        } else if (distance2 == minDistance) {
            _end1.x = end1.x + end2.x - start1.x
            _end1.y = end1.y + end2.y - start1.y
            return mathUtil.Angle(end2, _end1, start2)
        } else if (distance3 == minDistance) {
            _start1.x = start1.x + start2.x - end1.x
            _start1.y = start1.y + start2.y - end1.y
            return mathUtil.Angle(start2, _start1, end2)
        } else if (distance4 == minDistance) {
            _start1.x = start1.x + end2.x - end1.x
            _start1.y = start1.y + end2.y - end1.y
            return mathUtil.Angle(end2, _start1, start2)
        } else {
            console.error('WallService.AngleForWall3************************************1')
            return null
        }
    }

    // pointId的parent超过两个
    // 获取最小角度（顺时针和逆时针）
    // 可能缺顺时针或者逆时针，这时候对应的取最大角度的逆时针或者顺时针
    wallIdForMinAngle(pointId, wallId) {
        const point = floorplanService.getPoint(pointId)
        const parent = point.parent

        let minAngle0 = null
        let maxAngle0 = null // 可能minAngle1不存在，这时候要找逆时针最大的
        let minAngle1 = null
        let maxAngle1 = null

        let minInfo0, minInfo1
        let maxInfo0, maxInfo1

        if (Object.keys(parent).length > 2) {
            for (const key in parent) {
                if (key == wallId) {
                    continue
                }
                const angleInfo = this.AngleForWall2(wallId, key)
                if (minAngle1 == null && angleInfo.clockwise == 1) {
                    minInfo1 = angleInfo
                    minInfo1.wallId = key
                    minAngle1 = angleInfo.angle

                    maxInfo1 = angleInfo
                    maxInfo1.wallId = key
                    maxAngle1 = angleInfo.angle
                } else if (minAngle1 > angleInfo.angle && angleInfo.clockwise == 1) {
                    minInfo1 = angleInfo
                    minInfo1.wallId = key
                    minAngle1 = angleInfo.angle
                } else if (maxAngle1 < angleInfo.angle && angleInfo.clockwise == 1) {
                    maxInfo1 = angleInfo
                    maxInfo1.wallId = key
                    maxAngle1 = angleInfo.angle
                } else if (minAngle0 == null && angleInfo.clockwise == 0) {
                    minInfo0 = angleInfo
                    minInfo0.wallId = key
                    minAngle0 = angleInfo.angle

                    maxInfo0 = angleInfo
                    maxInfo0.wallId = key
                    maxAngle0 = angleInfo.angle
                } else if (minAngle0 > angleInfo.angle && angleInfo.clockwise == 0) {
                    minInfo0 = angleInfo
                    minInfo0.wallId = key
                    minAngle0 = angleInfo.angle
                } else if (maxAngle0 < angleInfo.angle && angleInfo.clockwise == 0) {
                    maxInfo0 = angleInfo
                    maxInfo0.wallId = key
                    maxAngle0 = angleInfo.angle
                }
            }

            const result = {
                min0: minInfo0,
                min1: minInfo1,
            }

            if (!result.min0) {
                result.min0 = maxInfo1
                result.min0.angle = 360 - maxInfo1.angle
            }

            if (!result.min1) {
                result.min1 = maxInfo0
                result.min1.angle = 360 - maxInfo0.angle
            }

            return result
        } else {
            console.error('wallIdForMinAngle*********************************************************')
            return null
        }
    }

    // wallId1和wallId2合并，其中，wallId1保留，wallId2删除
    // 返回目标点
    mergeWall(wallId1, wallId2) {
        const linkPointId = this.getLinkPointId(wallId1, wallId2)
        const wall2 = floorplanService.getWall(wallId2)
        const targetPointId = wall2.getOtherPointId(linkPointId)
        const targetPoint = floorplanService.getPoint(targetPointId)

        if (Object.keys(targetPoint.parent).length > 1) {
            // 将linkPointId 移动到 targetPointId
            this.moveTo(linkPointId, targetPointId)
        } else {
            // 删除墙wallId2
            floorplanService.deleteWall(wallId2)
            let linkPoint = floorplanService.getPoint(linkPointId)
            mathUtil.clonePoint(linkPoint, targetPoint)
        }
        return targetPointId
    }

    mergeWallForPoint(pointId) {
        const point = floorplanService.getPoint(pointId)
        if (point != null && Object.keys(point.parent).length == 2) {
            const angle = this.AngleForWall(Object.keys(point.parent)[0], Object.keys(point.parent)[1])
            if (angle > (Constant.maxAngle / 180) * Math.PI) {
                return this.mergeWall(Object.keys(point.parent)[0], Object.keys(point.parent)[1])
            }
        }
        return null
    }

    getLinkPointId(wallId1, wallId2) {
        const wall1 = floorplanService.getWall(wallId1)
        const wall2 = floorplanService.getWall(wallId2)

        if (wall1.start == wall2.start) {
            return wall1.start
        } else if (wall1.start == wall2.end) {
            return wall1.start
        } else if (wall1.end == wall2.start) {
            return wall1.end
        } else if (wall1.end == wall2.end) {
            return wall1.end
        } else if (wall1.start == wall2.start) {
            return null
        }
    }

    // pointId1移动到pointId2
    // 如果有一堵墙(wallId)的两头是pointId1和pointId2，那么这堵墙会被删除
    moveTo(pointId1, pointId2) {
        const wallId = this.getWallId(pointId1, pointId2)
        // 不能重合
        let point1 = floorplanService.getPoint(pointId1)
        let point2 = floorplanService.getPoint(pointId2)
        const dx = point1.x - point2.x
        const dy = point1.y - point2.y
        let parent1 = point1.parent
        const parent2 = point2.parent
        //确保pointId1与pointId2重合后，墙的角度不能太小
        for (const wallId1 in parent1) {
            if (wallId1 == wallId) {
                continue
            }

            const wall1 = floorplanService.getWall(wallId1)
            const otherPointId1 = wall1.getOtherPointId(pointId1)
            const otherPoint1 = floorplanService.getPoint(otherPointId1)

            for (const wallId2 in parent2) {
                if (wallId2 == wallId) {
                    continue
                }
                const wall2 = floorplanService.getWall(wallId2)
                const otherPointId2 = wall2.getOtherPointId(pointId2)
                const otherPoint2 = floorplanService.getPoint(otherPointId2)
                const angle = mathUtil.Angle(point2, otherPoint1, otherPoint2)
                if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) {
                    return false
                }
            }
        }
        // pointId1,pointId2属于同一堵墙
        if (wallId != null) {
            floorplanService.deleteWall(wallId)
        }

        point1 = floorplanService.getPoint(pointId1)
        point2 = floorplanService.getPoint(pointId2)
        if (!point1 || !point2) {
            return false
        }

        //准备合并
        for (const wallId1 in parent1) {
            const wall1 = floorplanService.getWall(wallId1)
            const otherPointId = wall1.getOtherPointId(pointId1)
            const _wallId = this.getWallId(otherPointId, pointId2)
            if (_wallId != null) {
                return false
            }

            // wall1上pointId1被pointId2取代
            if (wall1.start == pointId1) {
                floorplanService.deletePoint(wall1.start, wallId1)
                wall1.start = pointId2
                point2.setPointParent(wallId1, 'start')
            } else if (wall1.end == pointId1) {
                floorplanService.deletePoint(wall1.end, wallId1)
                wall1.end = pointId2
                point2.setPointParent(wallId1, 'end')
            } else {
                console.error('wallService.moveTo****************************************************')
            }
        }
        return true
    }

    getDirction(pointId, wallId) {
        const wall = floorplanService.getWall(wallId)
        if (wall.start == pointId) {
            return 'start'
        } else if (wall.end == pointId) {
            return 'end'
        } else {
            console.error('WallService.getDirction*******************************************************************************************')
            return null
        }
    }

    isOverlapForMergePoint(pointId1, pointId2) {
        const wallId = this.getWallId(pointId1, pointId2)
        // 不能重合
        const point1 = floorplanService.getPoint(pointId1)
        const point2 = floorplanService.getPoint(pointId2)
        const dx = point1.x - point2.x
        const dy = point1.y - point2.y
        const parent1 = point1.parent
        const parent2 = point2.parent
        for (const wallId1 in parent1) {
            if (wallId1 == wallId) {
                continue
            }
            const wall1 = floorplanService.getWall(wallId1)
            const otherPointId1 = wall1.getOtherPointId(pointId1)
            const otherPoint1 = floorplanService.getPoint(otherPointId1)
            const newPoint = {
                x: otherPoint1.x - dx,
                y: otherPoint1.y - dy,
            }
            for (const wallId2 in parent2) {
                if (wallId2 == wallId) {
                    continue
                }
                const wall2 = floorplanService.getWall(wallId2)
                const otherPointId2 = wall2.getOtherPointId(pointId2)
                const otherPoint2 = floorplanService.getPoint(otherPointId2)
                const angle = mathUtil.Angle(point2, newPoint, otherPoint2)
                if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) {
                    return true
                }
            }
        }
        return false
    }

    subtraWallFromIntersect(pointId, wallId) {
        const point = floorplanService.getPoint(pointId)
        const parent = point.parent
        const dir = this.getDirction(pointId, wallId)

        if (Object.keys(parent).length == 1) {
            return
        }

        // 第一步先断开链接
        delete parent[wallId]
        // 第二步先新建端点
        const newPoint = this.createPoint(point.x, point.y)
        // 第三步建立链接
        newPoint.setPointParent(wallId, dir)
        let wall = floorplanService.getWall(wallId)
        if (dir == 'start') {
            wall.start = newPoint.vectorId
        } else if (dir == 'end') {
            wall.end = newPoint.vectorId
        }
    }

    setWallInfo(wallInfo) {
        let wall = floorplanService.getWall(wallInfo.vectorId)
        wall.start = wallInfo.start
        wall.end = wallInfo.end
        wall.color = wallInfo.color
        return wall
    }

    setPointInfo(pointInfo) {
        let point = floorplanService.getPoint(pointInfo.vectorId)
        mathUtil.clonePoint(point, pointInfo.position)
        point.parent = JSON.parse(JSON.stringify(pointInfo.parent))
        return point
    }

    getNeighPoints(pointId, exceptPointId) {
        let points = []
        let point = floorplanService.getPoint(pointId)
        for (let key in point.parent) {
            let wall = floorplanService.getWall(key)
            const otherPointId = wall.getOtherPointId(pointId)
            if (exceptPointId && exceptPointId == otherPointId) {
                continue
            }
            const otherPoint = floorplanService.getPoint(otherPointId)
            points.push(otherPoint)
        }
        return points
    }

    deleteWallCorner(pointId) {
        let point = floorplanService.getPoint(pointId)
        if (Object.keys(point.parent).length == 1) {
            floorplanService.deleteWall(Object.keys(point.parent)[0])
        } else if (Object.keys(point.parent).length > 2) {
            for (let key in point.parent) {
                floorplanService.deleteWall(key)
            }
        } else if (Object.keys(point.parent).length == 2) {
            const angle = this.AngleForWall(Object.keys(point.parent)[0], Object.keys(point.parent)[1])
            if (angle > (Constant.maxAngle / 180) * Math.PI) {
                //合并
                this.mergeWall(Object.keys(point.parent)[0], Object.keys(point.parent)[1])
            } else {
                floorplanService.deleteWall(Object.keys(point.parent)[0])
                //上一个删除后，下面的数组只有一个元素了
                floorplanService.deleteWall(Object.keys(point.parent)[0])
            }
        }
    }
}

const wallService = new WallService()
export { wallService }
