import SwiftUI
import GRDB
import UniformTypeIdentifiers

struct SessionView: View {
    @Bindable var state: AppState
    @State private var sessions: [Session] = []
    @State private var selectedSessionId: Int64?
    @State private var showingNewSession = false
    @State private var newLabel = ""
    @State private var newNotes = ""
    @State private var sessionCancellable: DatabaseCancellable?

    var body: some View {
        GeometryReader { geo in
            if geo.size.width > 700 {
                wideLayout
            } else {
                compactLayout
            }
        }
        .sheet(isPresented: $showingNewSession) {
            newSessionSheet
        }
        .onAppear { startObserving() }
        .onDisappear { sessionCancellable?.cancel() }
    }

    private func startObserving() {
        sessionCancellable = Storage.shared.observeSessions { sessions in
            self.sessions = sessions
        }
    }

    // MARK: - Wide layout (iPad)

    private var wideLayout: some View {
        HStack(spacing: 0) {
            sessionList
                .frame(width: 300)
            Divider()
            if let sid = selectedSessionId, let session = sessions.first(where: { $0.id == sid }) {
                SessionDetailView(session: session, state: state)
            } else {
                Text("Select or create a session")
                    .foregroundStyle(.secondary)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
        }
    }

    // MARK: - Compact layout (iPhone)

    private var compactLayout: some View {
        NavigationStack {
            sessionList
                .navigationTitle("Sessions")
                .toolbar {
                    ToolbarItem(placement: .primaryAction) {
                        Button(action: { showingNewSession = true }) {
                            Image(systemName: "plus")
                        }
                    }
                }
                .navigationDestination(for: Int64.self) { sid in
                    if let session = sessions.first(where: { $0.id == sid }) {
                        SessionDetailView(session: session, state: state)
                            .navigationTitle(session.label ?? "Session")
                    }
                }
        }
    }

    // MARK: - Session list

    private var sessionList: some View {
        VStack(spacing: 0) {
            HStack {
                Text("Sessions")
                    .font(.headline)
                Spacer()
                Button(action: { showingNewSession = true }) {
                    Image(systemName: "plus.circle.fill")
                        .imageScale(.large)
                }
            }
            .padding()

            if sessions.isEmpty {
                VStack(spacing: 8) {
                    Text("No sessions")
                        .foregroundStyle(.secondary)
                    Text("Create a session to organize measurements")
                        .font(.caption)
                        .foregroundStyle(Color(white: 0.4))
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            } else {
                List(selection: $selectedSessionId) {
                    ForEach(sessions, id: \.id) { session in
                        NavigationLink(value: session.id!) {
                            sessionRow(session)
                        }
                        .tag(session.id!)
                    }
                    .onDelete { indices in
                        for idx in indices {
                            guard let sid = sessions[idx].id else { continue }
                            try? Storage.shared.deleteSession(sid)
                        }
                    }
                }
                .listStyle(.plain)
            }
        }
    }

    private func sessionRow(_ session: Session) -> some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(session.label ?? "Untitled")
                .font(.subheadline.weight(.medium))
            HStack {
                Text(session.startedAt, style: .date)
                Text(session.startedAt, style: .time)
            }
            .font(.caption)
            .foregroundStyle(.secondary)
            if let notes = session.notes, !notes.isEmpty {
                Text(notes)
                    .font(.caption)
                    .foregroundStyle(.tertiary)
                    .lineLimit(1)
            }
            let count = (try? Storage.shared.measurementCount(sessionId: session.id!)) ?? 0
            if count > 0 {
                Text("\(count) measurement\(count == 1 ? "" : "s")")
                    .font(.caption2)
                    .foregroundStyle(.secondary)
            }
        }
        .padding(.vertical, 4)
    }

    // MARK: - New session sheet

    private var newSessionSheet: some View {
        NavigationStack {
            Form {
                Section("Session Info") {
                    TextField("Name", text: $newLabel)
                    TextField("Notes (optional)", text: $newNotes, axis: .vertical)
                        .lineLimit(3...6)
                }
            }
            .navigationTitle("New Session")
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") {
                        showingNewSession = false
                        newLabel = ""
                        newNotes = ""
                    }
                }
                ToolbarItem(placement: .confirmationAction) {
                    Button("Create") {
                        let label = newLabel.trimmingCharacters(in: .whitespaces)
                        let notes = newNotes.trimmingCharacters(in: .whitespaces)
                        if let session = try? Storage.shared.createSession(label: label.isEmpty ? nil : label) {
                            if !notes.isEmpty {
                                try? Storage.shared.updateSession(session.id!, label: session.label, notes: notes)
                            }
                            selectedSessionId = session.id
                        }
                        showingNewSession = false
                        newLabel = ""
                        newNotes = ""
                    }
                    .disabled(newLabel.trimmingCharacters(in: .whitespaces).isEmpty)
                }
            }
        }
        .presentationDetents([.medium])
    }
}

// MARK: - Session detail

struct SessionDetailView: View {
    let session: Session
    @Bindable var state: AppState
    @State private var measurements: [Measurement] = []
    @State private var editing = false
    @State private var editLabel = ""
    @State private var editNotes = ""
    @State private var showingFileImporter = false
    @State private var showingShareSheet = false
    @State private var exportFileURL: URL?

    var body: some View {
        NavigationStack {
            VStack(alignment: .leading, spacing: 0) {
                header
                Divider()
                measurementsList
            }
        }
        .onAppear { loadMeasurements() }
        .onChange(of: session.id) { loadMeasurements() }
        .sheet(isPresented: $editing) { editSheet }
        .sheet(isPresented: $showingShareSheet) {
            if let url = exportFileURL {
                ShareSheet(items: [url])
            }
        }
        .fileImporter(
            isPresented: $showingFileImporter,
            allowedContentTypes: [.plainText],
            onCompletion: handleImportedFile
        )
    }

    private func loadMeasurements() {
        guard let sid = session.id else { return }
        measurements = (try? Storage.shared.fetchMeasurements(sessionId: sid)) ?? []
    }

    private func exportSession() {
        guard let sid = session.id else { return }
        do {
            let toml = try Storage.shared.exportSession(sid)
            let name = (session.label ?? "session").replacingOccurrences(of: " ", with: "_")
            let url = FileManager.default.temporaryDirectory.appendingPathComponent("\(name).toml")
            try toml.write(to: url, atomically: true, encoding: .utf8)
            exportFileURL = url
            showingShareSheet = true
        } catch {
            state.status = "Export failed: \(error.localizedDescription)"
        }
    }

    private func handleImportedFile(_ result: Result<URL, Error>) {
        switch result {
        case .success(let url):
            guard url.startAccessingSecurityScopedResource() else {
                state.status = "Cannot access file"
                return
            }
            defer { url.stopAccessingSecurityScopedResource() }
            do {
                let toml = try String(contentsOf: url, encoding: .utf8)
                let _ = try Storage.shared.importSession(from: toml)
                state.status = "Session imported"
            } catch {
                state.status = "Import failed: \(error.localizedDescription)"
            }
        case .failure(let error):
            state.status = "File error: \(error.localizedDescription)"
        }
    }

    private var header: some View {
        VStack(alignment: .leading, spacing: 4) {
            HStack {
                Text(session.label ?? "Untitled")
                    .font(.title2.bold())
                Spacer()
                Button(action: {
                    editLabel = session.label ?? ""
                    editNotes = session.notes ?? ""
                    editing = true
                }) {
                    Image(systemName: "pencil.circle")
                        .imageScale(.large)
                }
                Button(action: { exportSession() }) {
                    Image(systemName: "square.and.arrow.up")
                        .imageScale(.large)
                }
                Button(action: { showingFileImporter = true }) {
                    Image(systemName: "square.and.arrow.down")
                        .imageScale(.large)
                }
            }
            HStack {
                Text(session.startedAt, style: .date)
                Text(session.startedAt, style: .time)
            }
            .font(.subheadline)
            .foregroundStyle(.secondary)
            if let notes = session.notes, !notes.isEmpty {
                Text(notes)
                    .font(.body)
                    .foregroundStyle(.secondary)
            }
        }
        .padding()
    }

    @ViewBuilder
    private var measurementsList: some View {
        if measurements.isEmpty {
            VStack(spacing: 8) {
                Text("No measurements")
                    .foregroundStyle(.secondary)
                Text("Run a measurement to add data here")
                    .font(.caption)
                    .foregroundStyle(Color(white: 0.4))
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        } else {
            List {
                ForEach(measurements, id: \.id) { meas in
                    NavigationLink {
                        MeasurementDataView(measurement: meas)
                    } label: {
                        MeasurementRow(measurement: meas, state: state)
                    }
                }
                .onDelete { indices in
                    for idx in indices {
                        guard let mid = measurements[idx].id else { continue }
                        try? Storage.shared.deleteMeasurement(mid)
                    }
                    loadMeasurements()
                }
            }
            .listStyle(.plain)
        }
    }

    private var editSheet: some View {
        NavigationStack {
            Form {
                Section("Session Info") {
                    TextField("Name", text: $editLabel)
                    TextField("Notes", text: $editNotes, axis: .vertical)
                        .lineLimit(3...6)
                }
            }
            .navigationTitle("Edit Session")
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") { editing = false }
                }
                ToolbarItem(placement: .confirmationAction) {
                    Button("Save") {
                        guard let sid = session.id else { return }
                        let label = editLabel.trimmingCharacters(in: .whitespaces)
                        let notes = editNotes.trimmingCharacters(in: .whitespaces)
                        try? Storage.shared.updateSession(
                            sid,
                            label: label.isEmpty ? nil : label,
                            notes: notes.isEmpty ? nil : notes
                        )
                        editing = false
                    }
                }
            }
        }
        .presentationDetents([.medium])
    }
}

// MARK: - Measurement row

struct MeasurementRow: View {
    let measurement: Measurement
    @Bindable var state: AppState

    var body: some View {
        HStack {
            Label(typeLabel, systemImage: typeIcon)
            Spacer()
            VStack(alignment: .trailing) {
                Text("\(pointCount) pts")
                    .font(.caption.monospacedDigit())
                Text(measurement.startedAt, style: .time)
                    .font(.caption2)
                    .foregroundStyle(.secondary)
            }
        }
        .contentShape(Rectangle())
        .onTapGesture { state.loadMeasurement(measurement) }
        .contextMenu {
            Button {
                state.loadMeasurement(measurement)
            } label: {
                Label("Load", systemImage: "square.and.arrow.down")
            }
            Button {
                state.loadAsReference(measurement)
            } label: {
                Label("Load as Reference", systemImage: "line.horizontal.2.decrease.circle")
            }
        }
        .swipeActions(edge: .leading) {
            Button {
                state.loadAsReference(measurement)
            } label: {
                Label("Reference", systemImage: "line.horizontal.2.decrease.circle")
            }
            .tint(.orange)
        }
    }

    private var typeLabel: String {
        switch measurement.type {
        case "eis": "EIS"
        case "lsv": "LSV"
        case "amp": "Amp"
        case "chlorine": "Chlorine"
        case "ph": "pH"
        default: measurement.type
        }
    }

    private var typeIcon: String {
        switch measurement.type {
        case "eis": "waveform.path.ecg"
        case "lsv": "chart.xyaxis.line"
        case "amp": "bolt.fill"
        case "chlorine": "drop.fill"
        case "ph": "scalemass"
        default: "questionmark.circle"
        }
    }

    private var pointCount: Int {
        guard let mid = measurement.id else { return 0 }
        return (try? Storage.shared.dataPointCount(measurementId: mid)) ?? 0
    }
}

struct ShareSheet: UIViewControllerRepresentable {
    let items: [Any]
    func makeUIViewController(context: Context) -> UIActivityViewController {
        UIActivityViewController(activityItems: items, applicationActivities: nil)
    }
    func updateUIViewController(_ vc: UIActivityViewController, context: Context) {}
}
