import SwiftUI
import NucleicCore
import NucleicProtocol

/// The fleet activity bell (mesh casting): a toolbar button with an unread badge opening a
/// popover feed of notable events from **every** host on the mesh — finished/needs-input turns,
/// approvals, ships, transfers, dispatches — merged across origins and surviving late joins.
/// A passive history surface: it never alerts (the notification/alarm paths stay the only
/// alerting); rows deep-link to their session, local or remote, through `openSessionID`.
struct ActivityFeedBell: View {
    @Environment(AppStore.self) private var store
    @State private var showingPopover = false

    var body: some View {
        Button {
            showingPopover.toggle()
        } label: {
            Label("Activity", systemImage: "bell")
                .foregroundStyle(.primary)
                .overlay(alignment: .topTrailing) {
                    if store.feedUnreadCount > 0 {
                        Circle()
                            .fill(.red)
                            .frame(width: 7, height: 7)
                            .offset(x: 2, y: -1)
                    }
                }
        }
        .help("Fleet activity")
        .popover(isPresented: $showingPopover, arrowEdge: .bottom) {
            ActivityFeedList(dismiss: { showingPopover = false })
                .onAppear { store.markFeedSeen() }
        }
    }
}

/// The popover body: newest-first rows, capped by the feed itself.
private struct ActivityFeedList: View {
    @Environment(AppStore.self) private var store
    var dismiss: () -> Void

    var body: some View {
        Group {
            if store.activityFeed.isEmpty {
                VStack(spacing: 6) {
                    Image(systemName: "bell.slash")
                        .font(.title3)
                        .foregroundStyle(.secondary)
                    Text("No fleet activity yet")
                        .font(.callout)
                        .foregroundStyle(.secondary)
                    Text("Finished chats, approvals, ships, and transfers from every Mac and runner land here.")
                        .font(.caption)
                        .foregroundStyle(.tertiary)
                        .multilineTextAlignment(.center)
                }
                .padding(24)
                .frame(width: 320)
            } else {
                ScrollView {
                    LazyVStack(alignment: .leading, spacing: 0) {
                        ForEach(store.activityFeed.reversed()) { item in
                            ActivityFeedRow(item: item) {
                                store.openSessionID = item.event.sessionID
                                dismiss()
                            }
                            Divider().padding(.leading, 34)
                        }
                    }
                    .padding(.vertical, 6)
                }
                .frame(width: 360, height: min(480, CGFloat(store.activityFeed.count) * 52 + 16))
            }
        }
    }
}

private struct ActivityFeedRow: View {
    let item: ActivityFeedItem
    var open: () -> Void
    @State private var hovering = false

    private var event: FeedEvent { item.event }

    var body: some View {
        Button(action: open) {
            HStack(alignment: .top, spacing: 10) {
                Image(systemName: Self.icon(for: event.kind))
                    .foregroundStyle(Self.tint(for: event.kind))
                    .frame(width: 16)
                    .padding(.top, 2)
                VStack(alignment: .leading, spacing: 2) {
                    HStack(spacing: 6) {
                        Text(event.sessionTitle.isEmpty ? "Untitled chat" : event.sessionTitle)
                            .font(.callout.weight(.medium))
                            .lineLimit(1)
                        Spacer(minLength: 4)
                        Text(event.at, format: .relative(presentation: .named))
                            .font(.caption2)
                            .foregroundStyle(.tertiary)
                    }
                    Text(subtitle)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                        .lineLimit(2)
                }
            }
            .padding(.horizontal, 10)
            .padding(.vertical, 7)
            .frame(maxWidth: .infinity, alignment: .leading)
            .background(hovering ? Color.primary.opacity(0.06) : .clear, in: RoundedRectangle(cornerRadius: 6))
        }
        .buttonStyle(.plain)
        .onHover { hovering = $0 }
        .padding(.horizontal, 4)
    }

    private var subtitle: String {
        var parts: [String] = [Self.headline(for: event)]
        if !event.projectName.isEmpty { parts.append(event.projectName) }
        if !event.hostName.isEmpty { parts.append(event.hostName) }
        return parts.joined(separator: " · ")
    }

    static func headline(for event: FeedEvent) -> String {
        switch event.kind {
        case .finished: "Finished"
        case .needsInput: "Waiting for you"
        case .needsApproval: event.detail.map { "Needs approval: \($0)" } ?? "Needs approval"
        case .responded: event.detail ?? "Answered"
        case .shipped: event.detail.map { "Shipped · \($0)" } ?? "Shipped"
        case .transferredOut: "Moved to \(event.counterpartHostName ?? "another Mac")"
        case .transferredIn: "Arrived from \(event.counterpartHostName ?? "another Mac")"
        case .error: event.detail.map { "Error: \($0)" } ?? "Error"
        case .dispatched: "Dispatched here via Mesh"
        default: event.kind.rawValue  // a newer build's kind — render generically, never drop
        }
    }

    static func icon(for kind: FeedEvent.Kind) -> String {
        switch kind {
        case .finished: "checkmark.circle"
        case .needsInput: "bubble.left.and.exclamationmark.bubble.right"
        case .needsApproval: "hand.raised"
        case .responded: "hand.thumbsup"
        case .shipped: "arrow.triangle.merge"
        case .transferredOut: "arrow.up.right.square"
        case .transferredIn: "arrow.down.left.square"
        case .error: "exclamationmark.triangle"
        case .dispatched: "paperplane"
        default: "circle"
        }
    }

    static func tint(for kind: FeedEvent.Kind) -> Color {
        switch kind {
        case .finished, .shipped, .responded: .green
        case .needsInput, .needsApproval: .orange
        case .error: .red
        default: .secondary
        }
    }
}
