import IndieSync
import SwiftData
import SwiftUI

/// Sheet for filing one note under a project: pick an existing one, clear the
/// current assignment, or create a new one on the spot. Opened from a leading
/// swipe in `NotesListView`/`ProjectNotesView`.
struct AssignProjectSheet: View {
    let note: NoteEntity

    @Environment(SyncEngine.self) private var syncEngine
    @Environment(\.dismiss) private var dismiss
    @Query(sort: \NoteEntity.createdAt, order: .reverse) private var notes: [NoteEntity]

    @State private var newName = ""

    @AppStorage(ProjectsNaming.storageKey) private var namingRaw = ProjectsNaming.projects.rawValue
    private var naming: ProjectsNaming { ProjectsNaming(rawValue: namingRaw) ?? .projects }

    @AppStorage(ProjectsPrefs.declaredKey) private var declaredRaw = ""

    var body: some View {
        NavigationStack {
            List {
                if note.project != nil {
                    Section {
                        Button(role: .destructive) {
                            assign(nil)
                        } label: {
                            Label("Remove from \(naming.singular)", systemImage: "folder.badge.minus")
                        }
                    }
                }

                if !existingProjects.isEmpty {
                    Section(naming.plural) {
                        ForEach(existingProjects, id: \.project) { entry in
                            Button {
                                assign(entry.project)
                            } label: {
                                HStack {
                                    Label(entry.project, systemImage: "folder")
                                    Spacer()
                                    Text("\(entry.count)")
                                        .foregroundStyle(.secondary)
                                        .monospacedDigit()
                                    if note.project == entry.project {
                                        Image(systemName: "checkmark")
                                            .foregroundStyle(.tint)
                                    }
                                }
                            }
                            .buttonStyle(.plain)
                        }
                    }
                }

                Section("New \(naming.singular)") {
                    TextField("Name", text: $newName)
                        .autocorrectionDisabled()
                        #if os(iOS)
                        .textInputAutocapitalization(.words)
                        #endif
                    Button("File Under New \(naming.singular)") {
                        assign(trimmedNewName)
                    }
                    .disabled(trimmedNewName.isEmpty)
                }
            }
            .navigationTitle("File Under…")
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") { dismiss() }
                }
            }
        }
        .presentationDetents([.medium, .large])
    }

    private var trimmedNewName: String {
        newName.trimmingCharacters(in: .whitespacesAndNewlines)
    }

    /// Distinct project names across live notes, unioned with names declared
    /// but not yet used (count 0) so a freshly "+"-created project is
    /// immediately offered here, count-sorted like `ProjectsView` so the
    /// most-used projects surface first.
    private var existingProjects: [(project: String, count: Int)] {
        var counts: [String: Int] = [:]
        for note in notes where note.isLive {
            guard let project = note.project else { continue }
            counts[project, default: 0] += 1
        }
        for name in ProjectsPrefs.decodeDeclared(declaredRaw) where counts[name] == nil {
            counts[name] = 0
        }
        return counts
            .map { (project: $0.key, count: $0.value) }
            .sorted { $0.count == $1.count ? $0.project < $1.project : $0.count > $1.count }
    }

    private func assign(_ project: String?) {
        guard let id = ULID(string: note.id) else { return }
        Task {
            try? await syncEngine.assignProject(id: id, project: project)
            dismiss()
        }
    }
}
