import SwiftUI
import SwiftData
import VNCCore

public struct ConnectionListView: View {
    @Environment(\.modelContext) private var modelContext
    @Environment(\.openWindow) private var openWindow
    @Query(sort: \SavedConnection.displayName) private var connections: [SavedConnection]

    @State private var discovery = DiscoveryService()
    @State private var showingAdd = false
    @State private var showingSettings = false
    @State private var addPrefill: AddConnectionPrefill?
    @State private var editingConnection: SavedConnection?
    @State private var sessionConnection: SavedConnection?
    @State private var resolvingHostID: String?
    @State private var search = ""

    public init() {}

    public var body: some View {
        VStack(spacing: 0) {
            topChrome
            contentList
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
        .background(backgroundGradient.ignoresSafeArea())
        .sheet(isPresented: $showingAdd) {
            AddConnectionView(prefill: addPrefill)
        }
        .sheet(item: $editingConnection) { connection in
            AddConnectionView(editing: connection)
        }
        .sheet(isPresented: $showingSettings) {
            SettingsView()
        }
        #if os(iOS)
        .fullScreenCover(item: $sessionConnection) { connection in
            SessionView(connection: connection)
        }
        #else
        .sheet(item: $sessionConnection) { connection in
            SessionView(connection: connection)
        }
        #endif
        .task { discovery.start() }
        .onDisappear { discovery.stop() }
    }

    // MARK: Background

    private var backgroundGradient: some View {
        ZStack {
            LinearGradient(
                colors: [
                    Color(red: 0.06, green: 0.08, blue: 0.16),
                    Color(red: 0.02, green: 0.02, blue: 0.06)
                ],
                startPoint: .top,
                endPoint: .bottom
            )
            RadialGradient(
                colors: [Color.blue.opacity(0.20), .clear],
                center: .init(x: 0.5, y: 0.05),
                startRadius: 10,
                endRadius: 360
            )
            .blendMode(.screen)
            .allowsHitTesting(false)
        }
    }

    // MARK: Top chrome — flush with safe area top

    private var topChrome: some View {
        VStack(spacing: 12) {
            HStack(alignment: .center) {
                circularGlassButton(systemName: "gearshape", label: "Settings") {
                    showingSettings = true
                }
                Spacer()
                Text("Screens")
                    .font(.system(size: 26, weight: .bold, design: .rounded))
                    .foregroundStyle(.white)
                Spacer()
                circularGlassButton(systemName: "plus", label: "Add connection") {
                    addPrefill = nil
                    showingAdd = true
                }
            }
            searchField
        }
        .padding(.horizontal, 16)
        .padding(.top, 8)
        .padding(.bottom, 12)
    }

    private func circularGlassButton(systemName: String,
                                     label: String,
                                     action: @escaping () -> Void) -> some View {
        Button(action: action) {
            Image(systemName: systemName)
                .font(.callout.weight(.semibold))
                .foregroundStyle(.white)
                .frame(width: 38, height: 38)
        }
        .buttonStyle(.plain)
        .glassSurface(in: Circle())
        .accessibilityLabel(label)
    }

    private var searchField: some View {
        HStack(spacing: 10) {
            Image(systemName: "magnifyingglass")
                .foregroundStyle(.white.opacity(0.65))
            TextField("", text: $search, prompt: Text("Search connections")
                .foregroundStyle(.white.opacity(0.45)))
                .textFieldStyle(.plain)
                .foregroundStyle(.white)
                #if os(iOS)
                .textInputAutocapitalization(.never)
                #endif
                .autocorrectionDisabled()
                .submitLabel(.search)
            if !search.isEmpty {
                Button {
                    search = ""
                } label: {
                    Image(systemName: "xmark.circle.fill")
                        .foregroundStyle(.white.opacity(0.45))
                }
                .buttonStyle(.plain)
                .accessibilityLabel("Clear search")
            }
        }
        .padding(.horizontal, 14)
        .padding(.vertical, 11)
        .glassSurface(in: Capsule())
    }

    // MARK: Content

    private var contentList: some View {
        ScrollView {
            LazyVStack(spacing: 22) {
                if !discovery.hosts.isEmpty || discovery.isBrowsing {
                    discoveredSection
                }
                savedSection
                Color.clear.frame(height: 1) // bottom anchor
            }
            .padding(.horizontal, 16)
            .padding(.top, 4)
            .padding(.bottom, 24)
        }
        #if os(iOS)
        .scrollIndicators(.hidden)
        #endif
    }

    // MARK: Discovered

    private var discoveredSection: some View {
        VStack(alignment: .leading, spacing: 10) {
            sectionHeader("On this network",
                          systemImage: "antenna.radiowaves.left.and.right")

            VStack(spacing: 10) {
                if discovery.hosts.isEmpty {
                    HStack(spacing: 12) {
                        ProgressView().controlSize(.small).tint(.white)
                        Text("Looking for computers…")
                            .font(.callout)
                            .foregroundStyle(.white.opacity(0.7))
                        Spacer()
                    }
                    .padding(16)
                    .glassSurface(in: RoundedRectangle(cornerRadius: 18, style: .continuous))
                } else {
                    ForEach(discovery.hosts) { host in
                        Button {
                            Task { await prepareDiscoveredHost(host) }
                        } label: {
                            HStack(spacing: 14) {
                                ZStack {
                                    Circle()
                                        .fill(Color.blue.opacity(0.25))
                                        .frame(width: 38, height: 38)
                                    Image(systemName: "wifi")
                                        .font(.callout)
                                        .foregroundStyle(.blue)
                                }
                                VStack(alignment: .leading, spacing: 2) {
                                    Text(host.displayName)
                                        .font(.headline)
                                        .foregroundStyle(.white)
                                    Text(serviceLabel(host.serviceType))
                                        .font(.caption)
                                        .foregroundStyle(.white.opacity(0.6))
                                }
                                Spacer()
                                if resolvingHostID == host.id {
                                    ProgressView().controlSize(.small).tint(.white)
                                } else {
                                    Image(systemName: "plus.circle.fill")
                                        .font(.title3)
                                        .foregroundStyle(.blue)
                                }
                            }
                            .padding(14)
                        }
                        .buttonStyle(.plain)
                        .glassSurface(in: RoundedRectangle(cornerRadius: 18, style: .continuous))
                        .disabled(resolvingHostID != nil)
                    }
                }
            }
        }
    }

    // MARK: Saved

    private var savedSection: some View {
        VStack(alignment: .leading, spacing: 10) {
            sectionHeader("Saved", systemImage: "bookmark.fill")

            if filteredConnections.isEmpty {
                if connections.isEmpty {
                    emptySavedState
                } else {
                    noSearchResultsState
                }
            } else {
                VStack(spacing: 10) {
                    ForEach(filteredConnections) { connection in
                        connectionRow(connection)
                    }
                }
            }
        }
    }

    private var emptySavedState: some View {
        VStack(spacing: 14) {
            ZStack {
                Circle()
                    .fill(LinearGradient(colors: [.blue.opacity(0.4), .purple.opacity(0.3)],
                                         startPoint: .topLeading,
                                         endPoint: .bottomTrailing))
                    .frame(width: 64, height: 64)
                Image(systemName: "display")
                    .font(.title.weight(.semibold))
                    .foregroundStyle(.white)
            }
            Text("No saved connections")
                .font(.headline)
                .foregroundStyle(.white)
            Text("Tap + at the top to add a Mac, Linux box, or Raspberry Pi.")
                .font(.callout)
                .foregroundStyle(.white.opacity(0.65))
                .multilineTextAlignment(.center)
                .padding(.horizontal, 8)
            Button {
                addPrefill = nil
                showingAdd = true
            } label: {
                Label("Add a computer", systemImage: "plus")
                    .font(.callout.weight(.semibold))
                    .padding(.horizontal, 18)
                    .padding(.vertical, 12)
            }
            .buttonStyle(.plain)
            .background(
                Capsule().fill(LinearGradient(colors: [.blue, .purple],
                                              startPoint: .leading,
                                              endPoint: .trailing))
            )
            .foregroundStyle(.white)
        }
        .frame(maxWidth: .infinity)
        .padding(28)
        .glassSurface(in: RoundedRectangle(cornerRadius: 22, style: .continuous))
    }

    private var noSearchResultsState: some View {
        VStack(spacing: 8) {
            Image(systemName: "magnifyingglass")
                .font(.title)
                .foregroundStyle(.white.opacity(0.5))
            Text("No matches for \"\(search)\"")
                .font(.callout)
                .foregroundStyle(.white.opacity(0.65))
        }
        .frame(maxWidth: .infinity)
        .padding(24)
        .glassSurface(in: RoundedRectangle(cornerRadius: 18, style: .continuous))
    }

    private func connectionRow(_ connection: SavedConnection) -> some View {
        Button {
            sessionConnection = connection
        } label: {
            ConnectionCard(connection: connection)
                .padding(14)
        }
        .buttonStyle(.plain)
        .glassSurface(in: RoundedRectangle(cornerRadius: 18, style: .continuous))
        .contextMenu {
            Button {
                editingConnection = connection
            } label: {
                Label("Edit", systemImage: "pencil")
            }
            #if os(iOS)
            Button {
                openWindow(value: connection.id)
            } label: {
                Label("Open in New Window", systemImage: "rectangle.stack.badge.plus")
            }
            #endif
            Divider()
            Button(role: .destructive) {
                delete(connection)
            } label: {
                Label("Delete", systemImage: "trash")
            }
        }
    }

    // MARK: Helpers

    private func sectionHeader(_ title: String, systemImage: String) -> some View {
        HStack(spacing: 8) {
            Image(systemName: systemImage)
                .font(.caption.weight(.semibold))
            Text(title)
                .font(.subheadline.weight(.semibold))
                .textCase(.uppercase)
                .tracking(0.5)
        }
        .foregroundStyle(.white.opacity(0.55))
        .padding(.horizontal, 4)
    }

    private var filteredConnections: [SavedConnection] {
        let trimmed = search.trimmingCharacters(in: .whitespaces)
        guard !trimmed.isEmpty else { return connections }
        return connections.filter { connection in
            connection.displayName.localizedCaseInsensitiveContains(trimmed) ||
            connection.host.localizedCaseInsensitiveContains(trimmed)
        }
    }

    private func serviceLabel(_ raw: String) -> String {
        switch raw {
        case "_rfb._tcp": return "VNC (Screen Sharing)"
        case "_workstation._tcp": return "Apple workstation"
        default: return raw
        }
    }

    private func prepareDiscoveredHost(_ host: DiscoveredHost) async {
        resolvingHostID = host.id
        defer { resolvingHostID = nil }
        do {
            let resolved = try await discovery.resolve(host)
            addPrefill = AddConnectionPrefill(
                displayName: host.displayName,
                host: resolved.host,
                port: resolved.port
            )
        } catch {
            addPrefill = AddConnectionPrefill(
                displayName: host.displayName,
                host: "",
                port: 5900
            )
        }
        showingAdd = true
    }

    private func delete(_ connection: SavedConnection) {
        try? KeychainService().deletePassword(account: connection.keychainTag)
        modelContext.delete(connection)
        try? modelContext.save()
    }
}

struct SessionRoute: Hashable {
    let connectionID: UUID
}
