import SwiftUI
import Bedrock
import UniformTypeIdentifiers

struct InsightsView: View {
    @Bindable var store: RitualStore
    @State private var refreshToken = UUID()
    @State private var isEditing = false
    @State private var draggingCard: InsightCardType?
    @State private var cardOrder: [InsightCardType] = []
    @State private var lastDroppedCard: InsightCardType?

    private let columns = [
        GridItem(
            .adaptive(minimum: AppMetrics.Size.insightCardMinWidth),
            spacing: Design.Spacing.medium,
            alignment: .top
        )
    ]
    
    /// Cards in the current display order (uses local state during editing)
    private var orderedCards: [InsightCard] {
        let allCards = store.insightCards()
        let cardsByType = Dictionary(uniqueKeysWithValues: allCards.map { ($0.type, $0) })
        return cardOrder.compactMap { cardsByType[$0] }
    }

    var body: some View {
        NavigationStack {
            ScrollView(.vertical, showsIndicators: false) {
                VStack(alignment: .leading, spacing: Design.Spacing.large) {
                    // Grid with drag-and-drop support in edit mode
                    LazyVGrid(columns: columns, spacing: Design.Spacing.medium) {
                        ForEach(orderedCards) { card in
                            insightCardItem(card: card)
                        }
                    }
                    .animation(.spring(response: 0.3, dampingFraction: 0.7), value: cardOrder)
                    .onDrop(of: [.text], isTargeted: nil) { _ in
                        // Fallback drop handler - clear dragging state
                        lastDroppedCard = draggingCard
                        draggingCard = nil
                        return false
                    }
                }
                .padding(Design.Spacing.large)
            }
            .background(LinearGradient(
                colors: [AppSurface.primary, AppSurface.secondary],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            ))
            .navigationTitle(String(localized: "Insights"))
            .navigationBarTitleDisplayMode(.large)
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button {
                        withAnimation(.easeInOut(duration: Design.Animation.standard)) {
                            if isEditing {
                                // Save order and clear all drag state when exiting edit mode
                                draggingCard = nil
                                lastDroppedCard = nil
                                store.insightCardOrder = cardOrder
                            }
                            isEditing.toggle()
                        }
                    } label: {
                        Text(isEditing ? String(localized: "Done") : String(localized: "Edit"))
                            .foregroundStyle(AppAccent.primary)
                    }
                }
            }
            .onChange(of: isEditing) { _, newValue in
                // Clear all drag state when exiting edit mode
                if !newValue {
                    draggingCard = nil
                    lastDroppedCard = nil
                }
            }
            .onAppear {
                cardOrder = store.insightCardOrder
                Task {
                    await Task.yield()
                    store.refreshAnalyticsIfNeeded()
                    store.refreshInsightCardsIfNeeded()
                }
            }
            .onChange(of: store.rituals) { _, _ in
                store.refreshAnalyticsIfNeeded()
                store.refreshInsightCardsIfNeeded()
                cardOrder = store.insightCardOrder
            }
            .onChange(of: store.insightCardOrder) { _, newOrder in
                if !isEditing {
                    cardOrder = newOrder
                }
            }
        }
    }
    
    // MARK: - Card Item with Drag Support
    
    @ViewBuilder
    private func insightCardItem(card: InsightCard) -> some View {
        let isDragging = draggingCard == card.type
        
        let cardView = InsightCardView(card: card, store: store)
            .overlay(alignment: .topTrailing) {
                // Show drag handle in edit mode - sized to cover the disclosure chevron
                if isEditing {
                    Image(systemName: "line.3.horizontal")
                        .font(.body.weight(.medium))
                        .foregroundStyle(AppTextColors.inverse)
                        .padding(Design.Spacing.small)
                        .background(AppAccent.primary)
                        .clipShape(.rect(cornerRadius: Design.CornerRadius.small))
                        .padding(Design.Spacing.xSmall)
                }
            }
            .opacity(isDragging ? 0.3 : 1.0)
            .scaleEffect(isDragging ? 1.05 : (isEditing ? 0.98 : 1.0))
            .modifier(JiggleModifier(isEnabled: isEditing && draggingCard == nil))
        
        // Only enable drag when in edit mode
        if isEditing {
            cardView
                .onDrag {
                    // Prevent spurious re-trigger: if this is the same card that was just dropped
                    // and we're not currently dragging, ignore the call
                    let isSameAsLastDrop = lastDroppedCard == card.type
                    if !isSameAsLastDrop {
                        lastDroppedCard = nil
                        self.draggingCard = card.type
                    } else if draggingCard == nil {
                        // Spurious re-trigger - don't set draggingCard
                    }
                    return NSItemProvider(object: card.type.rawValue as NSString)
                }
                .onDrop(of: [.text], delegate: InsightCardDropDelegate(
                    card: card,
                    cardOrder: $cardOrder,
                    draggingCard: $draggingCard,
                    lastDroppedCard: $lastDroppedCard
                ))
        } else {
            cardView
        }
    }
}

// MARK: - Drop Delegate

struct InsightCardDropDelegate: DropDelegate {
    let card: InsightCard
    @Binding var cardOrder: [InsightCardType]
    @Binding var draggingCard: InsightCardType?
    @Binding var lastDroppedCard: InsightCardType?
    
    func performDrop(info: DropInfo) -> Bool {
        // Record which card was dropped BEFORE clearing draggingCard
        // This prevents spurious onDrag re-triggers from affecting state
        lastDroppedCard = draggingCard
        draggingCard = nil
        return true
    }
    
    func dropEntered(info: DropInfo) {
        guard let dragging = draggingCard, dragging != card.type else { return }
        
        guard let fromIndex = cardOrder.firstIndex(of: dragging),
              let toIndex = cardOrder.firstIndex(of: card.type),
              fromIndex != toIndex else {
            return
        }
        
        // Move the item with animation - updates local state, persisted when Done is tapped
        withAnimation(.spring(response: 0.3, dampingFraction: 0.7)) {
            let item = cardOrder.remove(at: fromIndex)
            cardOrder.insert(item, at: toIndex)
        }
    }
    
    func dropUpdated(info: DropInfo) -> DropProposal? {
        DropProposal(operation: .move)
    }
    
    func dropExited(info: DropInfo) {
        // Don't clear here - wait for performDrop
    }
}

// MARK: - Jiggle Animation Modifier

struct JiggleModifier: ViewModifier {
    let isEnabled: Bool
    @State private var isJiggling = false
    
    func body(content: Content) -> some View {
        content
            .rotationEffect(.degrees(isEnabled && isJiggling ? -1 : 0))
            .animation(
                isEnabled ? Animation.easeInOut(duration: 0.1).repeatForever(autoreverses: true) : .default,
                value: isJiggling
            )
            .onChange(of: isEnabled) { _, newValue in
                isJiggling = newValue
            }
            .onAppear {
                isJiggling = isEnabled
            }
    }
}

#Preview {
    InsightsView(store: RitualStore.preview)
}
