import ForgejoKit
import SwiftUI

// MARK: - Description Editor

struct DescriptionEditorSection: View {
    @Binding var text: String
    var title: String = "Description"
    var onUploadImage: ((Data, String, String) async throws -> String)?
    @State private var showingEditor = false

    var body: some View {
        Section(title) {
            Button {
                showingEditor = true
            } label: {
                if text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
                    Text("None")
                        .foregroundStyle(.secondary)
                } else {
                    MarkdownPreview(text: text)
                        .font(.subheadline)
                        .lineLimit(3)
                        // The preview renders selectable text and tappable links. Inside a
                        // Button label those intercept the tap, so the editor sheet never
                        // opens. Disable hit testing so the tap falls through to the Button.
                        .allowsHitTesting(false)
                }
            }
            .tint(.primary)
            .accessibilityIdentifier("description-edit-button")
            .sheet(isPresented: $showingEditor) {
                DescriptionEditorSheet(text: $text, title: title, onUploadImage: onUploadImage)
            }
        }
    }
}

private struct DescriptionEditorSheet: View {
    @Binding var text: String
    let title: String
    var onUploadImage: ((Data, String, String) async throws -> String)?
    @State private var selectedTab: EditPreviewTab = .edit
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        NavigationStack {
            MarkdownEditorField(
                text: $text,
                selectedTab: $selectedTab,
                showToolbar: true,
                onUploadImage: onUploadImage,
            )
            .frame(maxHeight: .infinity)
            .padding()
            .navigationTitle(title)
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button("Done") { dismiss() }
                }
            }
        }
    }
}

// MARK: - Picker Sheet (shared chrome)

private struct PickerSheet<Item: Identifiable, RowContent: View>: View {
    let title: String
    let items: [Item]
    let isSelected: (Item) -> Bool
    let onToggle: (Item) -> Void
    @ViewBuilder let rowContent: (Item) -> RowContent
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        NavigationStack {
            List {
                ForEach(items) { item in
                    Button {
                        onToggle(item)
                    } label: {
                        HStack {
                            rowContent(item)
                            Spacer()
                            if isSelected(item) {
                                Image(systemName: "checkmark")
                                    .foregroundStyle(.blue)
                            }
                        }
                    }
                    .tint(.primary)
                }
            }
            .navigationTitle(title)
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button("Done") { dismiss() }
                }
            }
        }
    }
}

// MARK: - Label Picker

struct LabelPickerSection: View {
    let availableLabels: [IssueLabel]
    @Binding var selectedLabelIDs: Set<Int>
    @State private var showingPicker = false

    private var selectedLabels: [IssueLabel] {
        availableLabels.filter { selectedLabelIDs.contains($0.id) }
    }

    var body: some View {
        Section("Labels") {
            if availableLabels.isEmpty {
                Text("No labels available")
                    .foregroundStyle(.secondary)
                    .font(.subheadline)
            } else {
                Button {
                    showingPicker = true
                } label: {
                    if selectedLabels.isEmpty {
                        Text("None")
                            .foregroundStyle(.secondary)
                    } else {
                        FlowLayout(spacing: 4) {
                            ForEach(selectedLabels) { label in
                                IssueLabelView(label: label)
                            }
                        }
                    }
                }
                .tint(.primary)
                .sheet(isPresented: $showingPicker) {
                    PickerSheet(
                        title: "Labels",
                        items: availableLabels,
                        isSelected: { selectedLabelIDs.contains($0.id) },
                        onToggle: { toggleLabel($0.id) },
                        rowContent: { IssueLabelView(label: $0) },
                    )
                }
            }
        }
    }

    private func toggleLabel(_ id: Int) {
        if selectedLabelIDs.contains(id) {
            selectedLabelIDs.remove(id)
        } else {
            selectedLabelIDs.insert(id)
        }
    }
}

// MARK: - Milestone Picker

struct MilestonePickerSection: View {
    let availableMilestones: [IssueMilestone]
    @Binding var selectedMilestoneID: Int?
    @State private var showingPicker = false

    private var selectedMilestone: IssueMilestone? {
        availableMilestones.first { $0.id == selectedMilestoneID }
    }

    var body: some View {
        Section("Milestone") {
            if availableMilestones.isEmpty {
                Text("No milestones available")
                    .foregroundStyle(.secondary)
                    .font(.subheadline)
            } else {
                Button {
                    showingPicker = true
                } label: {
                    if let milestone = selectedMilestone {
                        VStack(alignment: .leading) {
                            Text(milestone.title)
                                .font(.subheadline)
                            if let due = milestone.dueOn {
                                Text("Due \(due, style: .date)")
                                    .font(.caption)
                                    .foregroundStyle(.secondary)
                            }
                        }
                    } else {
                        Text("None")
                            .foregroundStyle(.secondary)
                    }
                }
                .tint(.primary)
                .sheet(isPresented: $showingPicker) {
                    PickerSheet(
                        title: "Milestone",
                        items: availableMilestones,
                        isSelected: { selectedMilestoneID == $0.id },
                        onToggle: { selectMilestone($0.id) },
                        rowContent: { milestone in
                            VStack(alignment: .leading) {
                                Text(milestone.title)
                                    .font(.subheadline)
                                if let due = milestone.dueOn {
                                    Text("Due \(due, style: .date)")
                                        .font(.caption)
                                        .foregroundStyle(.secondary)
                                }
                            }
                        },
                    )
                }
            }
        }
    }

    private func selectMilestone(_ id: Int) {
        if selectedMilestoneID == id {
            selectedMilestoneID = nil
        } else {
            selectedMilestoneID = id
        }
    }
}

// MARK: - User Picker (Assignees / Reviewers)

struct UserPickerSection: View {
    let title: String
    let availableUsers: [User]
    @Binding var selectedLogins: Set<String>
    @State private var showingPicker = false

    private var selectedUsers: [User] {
        availableUsers.filter { selectedLogins.contains($0.login) }
    }

    var body: some View {
        Section(title) {
            if availableUsers.isEmpty {
                Text("No \(title.lowercased()) available")
                    .foregroundStyle(.secondary)
                    .font(.subheadline)
            } else {
                Button {
                    showingPicker = true
                } label: {
                    if selectedUsers.isEmpty {
                        Text("None")
                            .foregroundStyle(.secondary)
                    } else {
                        Text(selectedUsers.map { $0.fullName ?? $0.login }.joined(separator: ", "))
                            .font(.subheadline)
                    }
                }
                .tint(.primary)
                .sheet(isPresented: $showingPicker) {
                    PickerSheet(
                        title: title,
                        items: availableUsers,
                        isSelected: { selectedLogins.contains($0.login) },
                        onToggle: { toggleUser($0.login) },
                        rowContent: { user in
                            VStack(alignment: .leading) {
                                Text(user.fullName ?? user.login)
                                    .font(.subheadline)
                                if user.fullName != nil {
                                    Text("@\(user.login)")
                                        .font(.caption)
                                        .foregroundStyle(.secondary)
                                }
                            }
                        },
                    )
                }
            }
        }
    }

    private func toggleUser(_ login: String) {
        if selectedLogins.contains(login) {
            selectedLogins.remove(login)
        } else {
            selectedLogins.insert(login)
        }
    }
}

#if DEBUG
    #Preview("Description") {
        @Previewable @State var text = "Some **markdown** description"
        NavigationStack {
            List {
                DescriptionEditorSection(text: $text)
            }
        }
    }

    #Preview("Labels") {
        @Previewable @State var selected: Set = [1]
        NavigationStack {
            List {
                LabelPickerSection(
                    availableLabels: IssueLabel.previewList,
                    selectedLabelIDs: $selected,
                )
            }
        }
    }

    #Preview("Milestones") {
        @Previewable @State var selected: Int?
        NavigationStack {
            List {
                MilestonePickerSection(
                    availableMilestones: [.preview],
                    selectedMilestoneID: $selected,
                )
            }
        }
    }

    #Preview("Users") {
        @Previewable @State var selected: Set<String> = []
        NavigationStack {
            List {
                UserPickerSection(
                    title: "Assignees",
                    availableUsers: [.preview, .previewBot],
                    selectedLogins: $selected,
                )
            }
        }
    }
#endif
