import Foundation
import SwiftUI

public struct TooltipBubbleShape: Shape {
    let anchor: Tooltip.Anchor
    let cornerRadius: CGFloat
    let triangleSize: CGFloat
    let triangleBase: CGFloat

    init(anchor: Tooltip.Anchor, style: Tooltip.Configuration.BubbleStyle) {
        self.anchor = anchor
        self.cornerRadius = style.cornerRadius
        self.triangleSize = style.triangleSize
        self.triangleBase = style.triangleBase
    }

    public func path(in rect: CGRect) -> Path {
        var path = Path()

        // Start with the main rounded rectangle
        let mainRect = getMainRect(in: rect)
        path.addPath(
            RoundedRectangle(
                cornerRadius: cornerRadius,
                style: .continuous
            ).path(in: mainRect)
        )

        let trianglePath = getTrianglePath(in: rect)
        path.addPath(trianglePath)

        return path
    }

    private func getMainRect(in rect: CGRect) -> CGRect {
        switch anchor {
        case .right:
            return rect.inset(by: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: triangleSize))
        case .left:
            return rect.inset(by: UIEdgeInsets(top: 0, left: triangleSize, bottom: 0, right: 0))
        case .up, .topLeft:
            return rect.inset(by: UIEdgeInsets(top: triangleSize, left: 0, bottom: 0, right: 0))
        case .down:
            return rect.inset(by: UIEdgeInsets(top: 0, left: 0, bottom: triangleSize, right: 0))
        }
    }

    private func getTrianglePath(in rect: CGRect) -> Path {
        var trianglePath = Path()

        switch anchor {
        case .right(let offset):
            let centerY = rect.midY + offset
            let points = [
                CGPoint(x: rect.maxX - triangleSize, y: centerY - triangleBase / 2),
                CGPoint(x: rect.maxX, y: centerY),
                CGPoint(x: rect.maxX - triangleSize, y: centerY + triangleBase / 2),
            ]
            trianglePath.addLines(points)

        case .left(let offset):
            let centerY = rect.midY + offset
            let points = [
                CGPoint(x: triangleSize, y: centerY - triangleBase / 2),
                CGPoint(x: 0, y: centerY),
                CGPoint(x: triangleSize, y: centerY + triangleBase / 2),
            ]
            trianglePath.addLines(points)

        case .up(let offset):
            let centerX = rect.midX + offset
            let points = [
                CGPoint(x: centerX - triangleBase / 2, y: triangleSize),
                CGPoint(x: centerX, y: 0),
                CGPoint(x: centerX + triangleBase / 2, y: triangleSize),
            ]
            trianglePath.addLines(points)

        case .down(let offset):
            let centerX = rect.midX + offset
            let points = [
                CGPoint(x: centerX - triangleBase / 2, y: rect.maxY - triangleSize),
                CGPoint(x: centerX, y: rect.maxY),
                CGPoint(x: centerX + triangleBase / 2, y: rect.maxY - triangleSize),
            ]
            trianglePath.addLines(points)

        case .topLeft(let offset):
            let originX = offset
            let points = [
                CGPoint(x: originX, y: triangleSize),
                CGPoint(x: originX + triangleBase / 2, y: 0),
                CGPoint(x: originX + triangleBase, y: triangleSize),
            ]
            trianglePath.addLines(points)
        }

        trianglePath.closeSubpath()
        return trianglePath
    }
}
