import OpenClawProtocol
import SwiftUI
import UIKit

struct AgentProNodesDestination: View {
    let headerLeadingAction: OpenClawSidebarHeaderAction?
    let overview: AgentOverviewSnapshot?
    let gatewayConnected: Bool
    let agentCount: Int
    let instancesValue: String
    let instancesDetail: String
    let instancesColor: Color
    let refresh: () async -> Void

    var body: some View {
        ZStack {
            OpenClawProBackground()
            ScrollView {
                VStack(alignment: .leading, spacing: 16) {
                    self.header
                    self.summaryCard
                    self.totalsCard
                    self.nodesList
                }
                .padding(.vertical, 18)
            }
            .refreshable {
                await self.refresh()
            }
            .safeAreaPadding(.bottom, OpenClawProMetric.bottomScrollInset)
        }
        .navigationTitle("Instances")
        .navigationBarTitleDisplayMode(.inline)
    }

    @ViewBuilder
    private var header: some View {
        if let headerLeadingAction {
            OpenClawAdaptiveHeaderRow(
                title: "Instances",
                subtitle: self.instancesDetail,
                titleFont: .title3.weight(.semibold),
                subtitleFont: .callout)
            {
                OpenClawSidebarHeaderLeadingSlot(action: headerLeadingAction)
            } accessory: {
                EmptyView()
            }
            .padding(.horizontal, OpenClawProMetric.pagePadding)
        }
    }

    private var summaryCard: some View {
        ProCard {
            HStack(spacing: 12) {
                ProIconBadge(systemName: "display", color: self.instancesColor)
                VStack(alignment: .leading, spacing: 3) {
                    Text("Instances")
                        .font(.headline)
                    Text(self.instancesDetail)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
                Spacer(minLength: 8)
                ProValuePill(value: self.instancesValue, color: self.instancesColor)
            }
        }
        .padding(.horizontal, OpenClawProMetric.pagePadding)
    }

    private var totalsCard: some View {
        ProCard {
            VStack(alignment: .leading, spacing: 12) {
                HStack {
                    Text("Presence")
                        .font(.headline)
                    Spacer()
                    ProValuePill(value: self.instancesValue, color: self.instancesColor)
                }
                HStack(spacing: 10) {
                    self.detailMetric(label: "Connected", value: "\(self.overview?.presence.count ?? 0)")
                    self.detailMetric(label: "Agents", value: "\(self.agentCount)")
                    self.detailMetric(label: "Gateway", value: self.gatewayConnected ? "online" : "offline")
                }
            }
        }
        .padding(.horizontal, OpenClawProMetric.pagePadding)
    }

    private var nodesList: some View {
        VStack(alignment: .leading, spacing: 8) {
            ProSectionHeader(title: "Connected Instances")
            ProCard(padding: 0) {
                let nodes = self.sortedPresenceEntries
                if nodes.isEmpty {
                    self.emptyRow(
                        icon: "display",
                        title: self.gatewayConnected ? "No instances connected" : "Instances unavailable",
                        detail: self.gatewayConnected
                            ? "The gateway did not report any system presence entries."
                            : "Connect a gateway to inspect connected instances.")
                        .padding(14)
                } else {
                    VStack(spacing: 0) {
                        ForEach(Array(nodes.enumerated()), id: \.element.presenceKey) { index, entry in
                            NavigationLink {
                                self.nodeDetail(entry)
                            } label: {
                                self.nodePresenceRow(entry, showsChevron: true)
                            }
                            .buttonStyle(.plain)
                            if index < nodes.count - 1 {
                                Divider().padding(.leading, 60)
                            }
                        }
                    }
                }
            }
            .padding(.horizontal, OpenClawProMetric.pagePadding)
        }
    }

    private var sortedPresenceEntries: [PresenceEntry] {
        (self.overview?.presence ?? [])
            .sorted { lhs, rhs in
                if lhs.ts != rhs.ts { return lhs.ts > rhs.ts }
                return (Self.presenceLabel(lhs) ?? lhs.presenceKey)
                    .localizedCaseInsensitiveCompare(Self.presenceLabel(rhs) ?? rhs.presenceKey) == .orderedAscending
            }
    }

    private func nodePresenceRow(_ entry: PresenceEntry, showsChevron: Bool = false) -> some View {
        HStack(alignment: .top, spacing: 12) {
            ProIconBadge(systemName: Self.presenceIcon(entry), color: Self.presenceColor(entry))
            VStack(alignment: .leading, spacing: 4) {
                Text(Self.presenceLabel(entry) ?? "Instance")
                    .font(.subheadline.weight(.semibold))
                    .lineLimit(1)
                Text(Self.presenceDetail(entry))
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .lineLimit(2)
                if let meta = Self.presenceMeta(entry) {
                    Text(meta)
                        .font(.caption2)
                        .foregroundStyle(.secondary)
                        .lineLimit(1)
                }
            }
            Spacer(minLength: 8)
            Text(Self.presenceState(entry))
                .font(.caption2.weight(.semibold))
                .foregroundStyle(Self.presenceColor(entry))
                .lineLimit(1)
            if showsChevron {
                Image(systemName: "chevron.right")
                    .font(.caption2.weight(.bold))
                    .foregroundStyle(.secondary)
                    .padding(.top, 2)
            }
        }
        .padding(.vertical, 10)
        .padding(.horizontal, 14)
    }

    private func nodeDetail(_ entry: PresenceEntry) -> some View {
        ZStack {
            OpenClawProBackground()
            ScrollView {
                VStack(alignment: .leading, spacing: 16) {
                    ProCard {
                        HStack(spacing: 12) {
                            ProIconBadge(systemName: Self.presenceIcon(entry), color: Self.presenceColor(entry))
                            VStack(alignment: .leading, spacing: 3) {
                                Text(Self.presenceLabel(entry) ?? "Instance")
                                    .font(.headline)
                                Text(Self.presenceDetail(entry))
                                    .font(.caption)
                                    .foregroundStyle(.secondary)
                            }
                            Spacer(minLength: 8)
                            ProValuePill(value: Self.presenceState(entry), color: Self.presenceColor(entry))
                        }
                    }
                    .padding(.horizontal, OpenClawProMetric.pagePadding)

                    ProCard {
                        VStack(spacing: 0) {
                            self.nodeDetailRow("Instance", value: entry.instanceid)
                            Divider()
                            self.nodeDetailRow("Device", value: entry.deviceid)
                            Divider()
                            self.nodeDetailRow("Host", value: entry.host)
                            Divider()
                            self.nodeDetailRow("IP", value: entry.ip)
                            Divider()
                            self.nodeDetailRow("Platform", value: entry.platform)
                            Divider()
                            self.nodeDetailRow("Version", value: entry.version)
                            Divider()
                            self.nodeDetailRow("Mode", value: entry.mode)
                        }
                    }
                    .padding(.horizontal, OpenClawProMetric.pagePadding)

                    self.nodeListCard(title: "Scopes", values: entry.scopes ?? [])
                    self.nodeListCard(title: "Roles", values: entry.roles ?? [])
                    self.nodeListCard(title: "Tags", values: entry.tags ?? [])
                }
                .padding(.vertical, 18)
            }
            .safeAreaPadding(.bottom, OpenClawProMetric.bottomScrollInset)
        }
        .navigationTitle(Self.presenceLabel(entry) ?? "Instance")
        .navigationBarTitleDisplayMode(.inline)
    }

    private func nodeDetailRow(_ title: String, value: String?) -> some View {
        let normalized = Self.normalized(value) ?? "n/a"
        return HStack(spacing: 10) {
            Text(title)
                .foregroundStyle(.secondary)
            Spacer(minLength: 8)
            Text(normalized)
                .lineLimit(1)
                .truncationMode(.middle)
            Button {
                UIPasteboard.general.string = normalized
            } label: {
                Image(systemName: "doc.on.doc")
            }
            .buttonStyle(.plain)
            .disabled(normalized == "n/a")
            .accessibilityLabel("Copy \(title)")
        }
        .font(.subheadline)
        .padding(.vertical, 10)
    }

    private func nodeListCard(title: String, values: [String]) -> some View {
        VStack(alignment: .leading, spacing: 8) {
            ProSectionHeader(title: title)
            ProCard {
                if values.isEmpty {
                    Text("None reported.")
                        .font(.subheadline)
                        .foregroundStyle(.secondary)
                        .frame(maxWidth: .infinity, alignment: .leading)
                } else {
                    VStack(alignment: .leading, spacing: 8) {
                        ForEach(values, id: \.self) { value in
                            Text(value)
                                .font(.caption.monospaced())
                                .textSelection(.enabled)
                                .frame(maxWidth: .infinity, alignment: .leading)
                        }
                    }
                }
            }
            .padding(.horizontal, OpenClawProMetric.pagePadding)
        }
    }

    private func detailMetric(label: String, value: String) -> some View {
        VStack(alignment: .leading, spacing: 3) {
            Text(label)
                .font(.caption2.weight(.medium))
                .foregroundStyle(.secondary)
            Text(value)
                .font(.subheadline.weight(.semibold))
                .lineLimit(1)
                .minimumScaleFactor(0.8)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(10)
        .background(Color.primary.opacity(0.055), in: RoundedRectangle(cornerRadius: 10, style: .continuous))
    }

    private func emptyRow(icon: String, title: String, detail: String) -> some View {
        HStack(spacing: 12) {
            ProIconBadge(systemName: icon, color: .secondary)
            VStack(alignment: .leading, spacing: 3) {
                Text(title)
                    .font(.subheadline.weight(.semibold))
                Text(detail)
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .lineLimit(2)
            }
            Spacer(minLength: 8)
        }
    }

    private static func presenceLabel(_ entry: PresenceEntry) -> String? {
        self.normalized(entry.host)
            ?? self.normalized(entry.devicefamily)
            ?? self.normalized(entry.platform)
            ?? self.normalized(entry.mode)
    }

    private static func presenceDetail(_ entry: PresenceEntry) -> String {
        let parts = [
            Self.normalized(entry.ip),
            Self.normalized(entry.platform),
            Self.normalized(entry.version),
        ].compactMap(\.self)
        if !parts.isEmpty {
            return parts.joined(separator: " • ")
        }
        return Self.normalized(entry.text) ?? "Presence beacon received."
    }

    private static func presenceMeta(_ entry: PresenceEntry) -> String? {
        let tags = (entry.tags ?? []).prefix(2).joined(separator: ", ")
        let scopesCount = entry.scopes?.count ?? 0
        let rolesCount = entry.roles?.count ?? 0
        let labels = [
            Self.normalized(entry.instanceid).map { "instance \($0)" },
            tags.isEmpty ? nil : tags,
            scopesCount > 0 ? "\(scopesCount) scopes" : nil,
            rolesCount > 0 ? "\(rolesCount) roles" : nil,
        ].compactMap(\.self)
        return labels.isEmpty ? nil : labels.joined(separator: " • ")
    }

    private static func presenceState(_ entry: PresenceEntry) -> String {
        if let reason = normalized(entry.reason) {
            return reason
        }
        if let mode = Self.normalized(entry.mode) {
            return mode
        }
        return Self.relativeTime(fromMilliseconds: entry.ts)
    }

    private static func presenceIcon(_ entry: PresenceEntry) -> String {
        let family = Self.normalized(entry.devicefamily)?.lowercased()
        if family?.contains("phone") == true { return "iphone" }
        if family?.contains("tablet") == true || family?.contains("pad") == true { return "ipad" }
        if family?.contains("desktop") == true || family?.contains("mac") == true { return "desktopcomputer" }
        return "display"
    }

    private static func presenceColor(_ entry: PresenceEntry) -> Color {
        self.normalized(entry.reason) == nil ? OpenClawBrand.accent : OpenClawBrand.warn
    }

    private static func normalized(_ value: String?) -> String? {
        let trimmed = value?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
        return trimmed.isEmpty ? nil : trimmed
    }

    private static func relativeTime(fromMilliseconds milliseconds: Int) -> String {
        let date = Date(timeIntervalSince1970: Double(milliseconds) / 1000)
        return date.formatted(.relative(presentation: .named, unitsStyle: .abbreviated))
    }
}

extension PresenceEntry {
    fileprivate var presenceKey: String {
        self.instanceid
            ?? self.deviceid
            ?? self.host
            ?? self.ip
            ?? "\(self.ts)"
    }
}
