import SwiftUI

public struct MoreButtonTooltipModifier: ViewModifier {
    @Binding var showTooltip: Bool
    @State private var shadowRadius: CGFloat = 4
    @State private var tooltipWidth: CGFloat = 0
    let accentColor: Color
    let buttonWidth: CGFloat
    let tooltip: Tooltip?
    let configuration: Tooltip.Configuration
    let onDismiss: () -> Void

    public init(
        showTooltip: Binding<Bool>,
        tooltip: Tooltip?,
        accentColor: Color,
        buttonWidth: CGFloat,
        onDismiss: @escaping () -> Void
    ) {
        self._showTooltip = showTooltip
        self.tooltip = tooltip
        self.accentColor = accentColor
        self.buttonWidth = buttonWidth
        self.configuration = tooltip?.configuration ?? .moreButtonOnOmniPlayer
        self.onDismiss = onDismiss
    }

    var tooltipPosition: CGPoint {
        return tooltipPosition(
            in: buttonWidth,
            for: tooltipWidth,
            anchor: configuration.anchor,
            spacing: configuration.spacing
        )
    }

    public func body(content: Content) -> some View {
        content
            .shadow(color: showTooltip ? accentColor : .clear, radius: showTooltip ? shadowRadius : 0)
            .overlay {
                if showTooltip, let tooltip {
                    TooltipView(
                        tooltip: tooltip,
                        maxWidth: configuration.maxWidth,
                        accentColor: accentColor,
                        onButtonTap: {
                            withAnimation(.easeInOut(duration: 0.2)) {
                                showTooltip = false
                                shadowRadius = 0
                            }
                            onDismiss()
                        }
                    )
                    .onGeometryChange(for: CGSize.self) { proxy in proxy.size } action: { size in
                        tooltipWidth = size.width
                    }
                    .transition(.scale(scale: 0.95).combined(with: .opacity).animation(.easeInOut(duration: 0.3)))
                    .offset(
                        x: tooltipPosition.x,
                        y: tooltipPosition.y
                    )
                    .zIndex(CGFloat.greatestFiniteMagnitude)
                }
            }
            .onChange(of: showTooltip) { _, isShowing in
                if isShowing {
                    withAnimation(.easeInOut(duration: 1.5).repeatForever(autoreverses: true)) {
                        shadowRadius = configuration.anchorObjectShadowRadius
                    }
                } else {
                    withAnimation(.easeInOut(duration: 0.2)) {
                        shadowRadius = 0
                    }
                }
            }
    }

    private func tooltipPosition(
        in buttonSize: CGFloat,
        for tooltipWidth: CGFloat,
        anchor: Tooltip.Anchor,
        spacing: CGFloat
    ) -> CGPoint {
        switch anchor {
        case .right(let offset):
            return CGPoint(
                x: -(tooltipWidth / 2 + spacing + buttonSize / 2),
                y: -offset
            )

        case .left(let offset):
            return CGPoint(
                x: tooltipWidth / 2 + spacing + buttonSize / 2,
                y: -offset
            )

        default:
            // More button tooltip only supports left/right positioning
            return CGPoint(x: 0, y: 0)
        }
    }
}
