import SwiftUI
import CoreBluetooth

struct TerminalView: View {
    @EnvironmentObject var ble: BluetoothManager
    @Environment(\.dismiss) private var dismiss

    @State private var inputText = ""
    @State private var inputMode: InputMode = .text
    @State private var displayMode: DisplayMode = .auto
    @State private var showServices = false
    @State private var autoscroll = true

    var body: some View {
        VStack(spacing: 0) {
            modeBar
            Divider()
            logView
            Divider()
            inputBar
        }
        .navigationTitle(ble.connectedPeripheral?.name ?? "Terminal")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Menu {
                    Button("Services & Characteristics") { showServices = true }
                    Button("Clear Log", role: .destructive) { ble.clearLog() }
                    Button("Disconnect", role: .destructive) {
                        ble.disconnect()
                        dismiss()
                    }
                } label: {
                    Image(systemName: "ellipsis.circle")
                }
            }
        }
        .sheet(isPresented: $showServices) {
            ServicesView()
                .environmentObject(ble)
        }
        .onDisappear {
            if ble.connectedPeripheral != nil { ble.disconnect() }
        }
    }

    // MARK: Mode bar

    private var modeBar: some View {
        HStack(spacing: 8) {
            Label("Display:", systemImage: "eye")
                .font(.caption)
                .foregroundColor(.secondary)
            Picker("Display", selection: $displayMode) {
                ForEach(DisplayMode.allCases, id: \.self) { Text($0.rawValue).tag($0) }
            }
            .pickerStyle(.segmented)
            .frame(maxWidth: 220)

            Spacer()

            Button {
                autoscroll.toggle()
            } label: {
                Image(systemName: "arrow.down.to.line")
                    .font(.caption)
                    .foregroundColor(autoscroll ? .accentColor : .secondary)
            }
        }
        .padding(.horizontal, 12)
        .padding(.vertical, 6)
        .background(Color(.systemGroupedBackground))
    }

    // MARK: Log

    private var logView: some View {
        ScrollViewReader { proxy in
            ScrollView {
                LazyVStack(alignment: .leading, spacing: 2) {
                    ForEach(ble.terminalLog) { entry in
                        LogEntryRow(entry: entry, displayMode: displayMode)
                            .id(entry.id)
                    }
                }
                .padding(8)
            }
            .background(Color.black)
            .onChange(of: ble.terminalLog.count) { _ in
                if autoscroll, let last = ble.terminalLog.last {
                    withAnimation { proxy.scrollTo(last.id, anchor: .bottom) }
                }
            }
        }
    }

    // MARK: Input bar

    private var inputBar: some View {
        VStack(spacing: 0) {
            HStack(spacing: 0) {
                Picker("Input", selection: $inputMode) {
                    ForEach(InputMode.allCases, id: \.self) { Text($0.rawValue).tag($0) }
                }
                .pickerStyle(.segmented)
                .frame(width: 120)
                .padding(.horizontal, 8)

                TextField(inputMode == .text ? "Enter text…" : "hex: 01 A2 FF",
                          text: $inputText)
                    .font(.system(.body, design: .monospaced))
                    .autocapitalization(.none)
                    .disableAutocorrection(true)
                    .padding(.horizontal, 8)
                    .padding(.vertical, 6)
                    .background(Color(.systemGray6))
                    .clipShape(RoundedRectangle(cornerRadius: 8))
                    .onSubmit { send() }

                Button(action: send) {
                    Image(systemName: "paperplane.fill")
                        .padding(.horizontal, 12)
                        .padding(.vertical, 8)
                        .background(canSend ? Color.accentColor : Color.gray)
                        .foregroundColor(.white)
                        .clipShape(RoundedRectangle(cornerRadius: 8))
                }
                .disabled(!canSend)
                .padding(.horizontal, 8)
            }
            .padding(.vertical, 8)
            .background(Color(.systemBackground))

            // Selected characteristic indicator
            if let char = ble.selectedWriteCharacteristic {
                Text("TX → \(char.uuid.uuidString.prefix(8))… (\(charProps(char)))")
                    .font(.caption2)
                    .foregroundColor(.secondary)
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .padding(.horizontal, 16)
                    .padding(.bottom, 4)
            } else {
                Text("No writable characteristic found")
                    .font(.caption2)
                    .foregroundColor(.orange)
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .padding(.horizontal, 16)
                    .padding(.bottom, 4)
            }
        }
    }

    // MARK: Helpers

    private var canSend: Bool {
        ble.selectedWriteCharacteristic != nil && !inputText.trimmingCharacters(in: .whitespaces).isEmpty
    }

    private func send() {
        guard !inputText.isEmpty else { return }
        switch inputMode {
        case .text: ble.sendText(inputText)
        case .hex:  ble.sendHex(inputText)
        }
        inputText = ""
    }

    private func charProps(_ char: CBCharacteristic) -> String {
        var p = [String]()
        if char.properties.contains(.write)               { p.append("write") }
        if char.properties.contains(.writeWithoutResponse){ p.append("writeNoRsp") }
        return p.joined(separator: ", ")
    }
}

// MARK: - Log Entry Row

struct LogEntryRow: View {
    let entry: TerminalEntry
    let displayMode: DisplayMode

    var body: some View {
        HStack(alignment: .top, spacing: 6) {
            // Direction indicator
            Text(directionTag)
                .font(.system(.caption2, design: .monospaced))
                .foregroundColor(directionColor)
                .frame(width: 36, alignment: .trailing)

            // Timestamp
            Text(entry.timestampText)
                .font(.system(.caption2, design: .monospaced))
                .foregroundColor(.gray)

            // Content
            Text(entry.displayText(mode: displayMode))
                .font(.system(.body, design: .monospaced))
                .foregroundColor(contentColor)
                .frame(maxWidth: .infinity, alignment: .leading)
        }
    }

    private var directionTag: String {
        switch entry.direction {
        case .sent:     return ">>>"
        case .received: return "<<<"
        case .info:     return "---"
        }
    }

    private var directionColor: Color {
        switch entry.direction {
        case .sent:     return Color(red: 0, green: 0.9, blue: 1)
        case .received: return .green
        case .info:     return .yellow
        }
    }

    private var contentColor: Color {
        switch entry.direction {
        case .sent:     return Color(white: 0.85)
        case .received: return .white
        case .info:     return .yellow
        }
    }
}
