import ComponentLibrary
import ComposableArchitecture
import FeatureRoot
import NukeUI
import SunoModelClient
import SwiftUI
import TabBarUtilities
import Utilities

public struct CustomTabBar: View {
    @Bindable var store: StoreOf<RootTabCoordinator>

    public init(store: StoreOf<RootTabCoordinator>) {
        self.store = store
    }

    private var tabBarAccent: Color {
        Color.SemanticV2.foregroundPrimary
    }

    private var tabBarCreateBackground: some View {
        #if targetEnvironment(simulator)
            Color.orange
        #else
            AuraShaderView(
                id: "welcome-screen",
                appPreset: .pinkYellowOrange,
                morphSpeed: 0.025,
                scale: 0.6,
                seed: 0
            )
        #endif
    }

    public let tabBarHeight: CGFloat = CustomBottomBarConstants.tabBarHeight
    public let tabBarTopPadding: CGFloat = CustomBottomBarConstants.tabBarTopPadding
    public let tabBarTopHairlineHeight: CGFloat = CustomBottomBarConstants.tabBarTopHairlineHeight

    public var body: some View {
        HStack(alignment: .center, spacing: 0) {
            // Discover tab
            tabButton(
                icon: store.selectedTab == .discover ? Image.Icon.homeTabIconSelected : Image.Icon.homeTabIcon,
                isSelected: store.selectedTab == .discover,
                tab: .discover,
                accentColor: tabBarAccent
            )

            // Library tab
            tabButton(
                icon: Image.Icon.libraryTabIcon,
                isSelected: store.selectedTab == .library,
                tab: .library,
                accentColor: tabBarAccent
            )

            // Create button
            createButton

            // Notifications tab
            badgedTabButton(
                image: store.selectedTab == .notifications ? UIImage.Icon.notificationsTabIconSelected : UIImage.Icon.notificationsTabIcon,
                isSelected: store.selectedTab == .notifications,
                showBadge: store.hasUnreadNotifications,
                tab: .notifications,
                accentColor: tabBarAccent
            )

            // Profile tab
            profileTabButton(
                profileImageURL: store.me.user.avatarImageUrl.map(URL.init(string:)) ?? .none,
                isSelected: store.selectedTab == .profile,
                tab: .profile,
                accentColor: tabBarAccent
            )
            .padding(.bottom, 1) // Visual offset to align when the tab is selected
        }
        .padding(.top, tabBarTopPadding)
        .frame(height: tabBarHeight)
        .background {
            Color.SemanticV1.backgroundPrimary
                .overlay(
                    Rectangle()
                        .frame(height: tabBarTopHairlineHeight)
                        .foregroundColor(Color.SemanticV1.tabBarHairline),
                    alignment: .top
                )
                .ignoresSafeArea(edges: .bottom)
        }
        .accentColor(tabBarAccent)
    }

    // Used on the Discover and Library tabs
    private func tabButton(
        icon: Image,
        isSelected: Bool,
        tab: TabBarTab,
        accentColor: Color
    ) -> some View {
        TabBarButton(
            icon: { icon },
            isSelected: isSelected,
            tab: tab,
            accentColor: accentColor,
            singleTapAction: {
                store.send(.popToRoot(tab: tab))
            },
            doubleTapAction: {
                store.send(.scrollToTop(tab: tab))
            },
            longPressAction: {
                store.send(.longPressAction(tab: tab))
            },
            didSelectTab: {
                store.selectedTab = tab
            }
        )
    }

    // Used on the Profile tab
    private func profileTabButton(
        profileImageURL: URL?,
        isSelected: Bool,
        tab: TabBarTab,
        accentColor: Color
    ) -> some View {
        TabBarButton(
            icon: {
                NukeUI.LazyImage(url: profileImageURL) {
                    ($0.image ?? Image(systemName: "circle.fill"))
                        .resizable()
                        .frame(width: 22, height: 22)
                        .clipShape(Circle())
                        .foregroundStyle(Color.SemanticV1.iconSecondary)
                        .overlay {
                            if isSelected {
                                Circle()
                                    .strokeBorder(Color.SemanticV1.iconLink, lineWidth: 1.6)
                                    .frame(width: 28, height: 28)
                            }
                        }
                }
            },
            isSelected: isSelected,
            tab: tab,
            accentColor: accentColor,
            singleTapAction: {
                store.send(.popToRoot(tab: tab))
            },
            doubleTapAction: {
                store.send(.scrollToTop(tab: tab))
            },
            longPressAction: {
                store.send(.longPressAction(tab: tab))
            },
            didSelectTab: {
                store.selectedTab = tab
            }
        )
    }

    // Used on the Notifications tab
    private func badgedTabButton(
        image: UIImage,
        isSelected: Bool,
        showBadge: Bool,
        tab: TabBarTab,
        accentColor: Color
    ) -> some View {
        TabBarButton(
            icon: {
                ZStack {
                    Image(uiImage: image)
                        .renderingMode(.template)
                        .foregroundColor(isSelected ? accentColor : Color.SemanticV1.foregroundInactive)

                    if showBadge {
                        Circle()
                            .fill(Color.SemanticV1.auraPink)
                            .frame(width: 6, height: 6)
                            .offset(x: 12, y: -12)
                    }
                }
            },
            isSelected: isSelected,
            tab: tab,
            accentColor: accentColor,
            singleTapAction: {
                store.send(.popToRoot(tab: tab))
            },
            doubleTapAction: {
                store.send(.scrollToTop(tab: tab))
            },
            longPressAction: {
                store.send(.longPressAction(tab: tab))
            },
            didSelectTab: {
                store.selectedTab = tab
            }
        )
    }

    // Create button
    @State private var createButtonHapticProxy = false

    private var createButton: some View {
        Button {
            createButtonHapticProxy.toggle()
            store.send(.createTapped)
        } label: {
            if #available(iOS 26.0, *) {
                ZStack {
                    tabBarCreateBackground
                    Image.Icon.createTabIcon
                        .foregroundColor(.white)
                }
                .clipShape(Capsule())
                .frame(width: 64, height: 40)
                .glassEffect(.regular.interactive())
            } else {
                ZStack {
                    tabBarCreateBackground
                    Image.Icon.createTabIcon
                        .foregroundColor(.white)
                }
                .clipShape(Capsule())
                .contentShape(Capsule())
                .frame(width: 64, height: 40)
            }
        }
        .buttonStyle(ScaleButtonStyle(scaleAmount: 0.98, minimumOpacity: 1))
        .padding(.bottom, UIScreen.isCompact ? 2 : 0)
        .padding(.horizontal, 6)
        .sensoryFeedbackIfEnabled(.impact(weight: .medium), trigger: createButtonHapticProxy)
    }
}

/*
 Generic TabBarTab Bar Button that can be used to display an icon,
 image, icon with a badge, etc.

 This does not use `onTapGesture(count: numberOfTaps)` to detect
 double taps because it introduces a slight delay to the
 single tap, which would cause slow tab switching if the user is
 on another tab and not trying to just pop the current tab to root.
 */
public struct TabBarButton<IconView: View>: View {
    @ViewBuilder var icon: () -> IconView
    @State private var hapticProxy: Bool = false
    @State private var isAnimatingReloadIcon: Bool = false
    @State private var lastTapTime: Date = .distantPast
    @State private var singleTapTask: Task<Void, Never>?
    let isSelected: Bool
    let tab: TabBarTab
    let accentColor: Color
    let singleTapAction: () -> Void
    let doubleTapAction: () -> Void
    let longPressAction: () -> Void
    let didSelectTab: () -> Void
    let doubleTapThresholdSeconds = 0.3
    let longPressThresholdSeconds = 1.0
    let isReloading: Bool

    public init(
        icon: @escaping () -> IconView,
        isSelected: Bool,
        tab: TabBarTab,
        accentColor: Color,
        isReloading: Bool = false,
        singleTapAction: @escaping () -> Void,
        doubleTapAction: @escaping () -> Void,
        longPressAction: @escaping () -> Void,
        didSelectTab: @escaping () -> Void
    ) {
        self.icon = icon
        self.isSelected = isSelected
        self.tab = tab
        self.accentColor = accentColor
        self.singleTapAction = singleTapAction
        self.doubleTapAction = doubleTapAction
        self.longPressAction = longPressAction
        self.didSelectTab = didSelectTab
        self.isReloading = isReloading
    }

    @ViewBuilder
    private var iconView: some View {
        ZStack {
            if !isReloading {
                icon()
                    .frame(width: 24, height: 24)
                    .transition(.scale(scale: 0.3).combined(with: .opacity))
            }

            // Show a spinning reload icon when reloading the Hooks feed
            if isReloading {
                Image.Icon.restart
                    .resizable()
                    .frame(width: 24, height: 24)
                    .foregroundColor(Color.SemanticV1.iconPrimary)
                    .rotationEffect(.degrees(isAnimatingReloadIcon ? -360 : 0))
                    .animation(.linear(duration: 1).repeatForever(autoreverses: false), value: isAnimatingReloadIcon)
                    .transition(.scale(scale: 0.5).combined(with: .opacity))
                    .onAppear {
                        isAnimatingReloadIcon = true
                    }
                    .onDisappear {
                        isAnimatingReloadIcon = false
                    }
            }
        }
        .frame(width: 24, height: 24)
        .animation(.easeInOut(duration: 0.3), value: isReloading)
    }

    public var body: some View {
        iconView
            .foregroundColor(isSelected ? accentColor : Color.SemanticV1.foregroundInactive)
            .frame(width: 24, height: 24)
            .frame(maxWidth: .infinity)
            .contentShape(Rectangle())
            .onTapGesture {
                let now = Date()

                if !isSelected {
                    didSelectTab()
                    return
                }

                if now.timeIntervalSince(lastTapTime) < doubleTapThresholdSeconds {
                    singleTapTask?.cancel()
                    doubleTapAction()
                } else {
                    singleTapTask?.cancel()
                    singleTapTask = Task { @MainActor in
                        try? await Task.sleep(nanoseconds: 250_000_000)
                        guard !Task.isCancelled else { return }
                        singleTapAction()
                    }
                }
                lastTapTime = now
            }
            .onLongPressGesture(minimumDuration: longPressThresholdSeconds) {
                longPressAction()
                hapticProxy.toggle()
            }
            .sensoryFeedbackIfEnabled(.selection, trigger: hapticProxy)
    }
}
