import AppKit
import SwiftUI

// MARK: - Reusable Tag Editor (overlay edit mode + Preferences)

/// A scrollable tag list with inline rename, color swatches, delete, and add-new-tag.
/// All changes (rename, delete, setColor) are saved to the local tag database.
struct TagEditorView: View {
    @Binding var tagColors: [String: Int]
    @Binding var tagCustomColors: [String: TagCustomColor]
    let excludedTagNames: Set<String>
    let isCustomColorUnlocked: Bool
    let onLockedCustomColor: () -> Void
    var topLeadingAccessory: AnyView? = nil
    var onRefresh: (() -> Void)?

    @State private var editingTagName: String? = nil
    @State private var editingTagText: String = ""
    @State private var addingNewTag = false
    @State private var newTagNameText = ""
    @State private var newTagColorIndex = 0

    private let contentMaxWidth: CGFloat = 980
    private let contentHorizontalPadding: CGFloat = 34

    private var sortedTagNames: [String] {
        let order = TagEditor.orderedTagNames()
        let filtered = tagColors.keys.filter { !excludedTagNames.contains($0) }
        let ordered = order.filter { filtered.contains($0) }
        let remaining = filtered.filter { !ordered.contains($0) }.sorted()
        return ordered + remaining
    }

    var body: some View {
        VStack(spacing: 0) {
            // "New Tag" button at top
            HStack {
                if let topLeadingAccessory {
                    topLeadingAccessory
                        .frame(maxWidth: .infinity, alignment: .leading)
                } else {
                    Spacer()
                }

                Button {
                    addingNewTag = true
                    newTagNameText = ""
                    newTagColorIndex = 0
                } label: {
                    Label(tr("tag.newTag"), systemImage: "plus")
                        .font(.system(size: 12))
                }
                .buttonStyle(.bordered)
            }
            .frame(maxWidth: contentMaxWidth)
            .padding(.horizontal, contentHorizontalPadding)
            .padding(.vertical, 8)

            Divider()
                .opacity(0.3)
                .frame(maxWidth: contentMaxWidth)
                .padding(.horizontal, contentHorizontalPadding)

            ScrollView {
                VStack(spacing: 0) {
                    if sortedTagNames.isEmpty && !addingNewTag {
                        Text(tr("edit.noTags"))
                            .font(.caption)
                            .foregroundStyle(.secondary)
                            .padding(.vertical, 40)
                    }
                    if addingNewTag {
                        newTagRow()
                        rowDivider
                    }
                    ForEach(sortedTagNames, id: \.self) { tagName in
                        tagEditRow(tagName)
                        rowDivider
                    }
                }
                .frame(maxWidth: contentMaxWidth)
                .padding(.horizontal, contentHorizontalPadding)
                .frame(maxWidth: .infinity, alignment: .center)
            }
        }
        .frame(maxWidth: .infinity, alignment: .center)
    }

    private var rowDivider: some View {
        Divider()
            .opacity(0.15)
            .frame(maxWidth: contentMaxWidth)
    }

    // MARK: - Tag Row

    private func tagEditRow(_ tagName: String) -> some View {
        let colorIndex = tagColors[tagName] ?? 0
        let hasCustomColor = tagCustomColors[tagName] != nil
        return HStack(spacing: 10) {
            HStack(spacing: 4) {
                ForEach(TagColor.allIndices, id: \.self) { idx in
                    ColorSwatch(index: idx, isSelected: !hasCustomColor && idx == colorIndex) {
                        TagEditor.setColor(idx, for: tagName)
                        tagColors[tagName] = idx
                        tagCustomColors.removeValue(forKey: tagName)
                        onRefresh?()
                    }
                }
            }

            customColorControl(tagName: tagName, colorIndex: colorIndex)

            if editingTagName == tagName {
                MacTextField(
                    text: $editingTagText,
                    placeholder: tr("tag.name"),
                    onSubmit: { commitTagRename(tagName) }
                )
                .frame(minWidth: 220, maxWidth: .infinity, minHeight: 24, maxHeight: 24)
                Button(tr("tag.save")) { commitTagRename(tagName) }
                    .buttonStyle(.borderedProminent).controlSize(.small)
                Button(tr("tag.cancel")) { editingTagName = nil }
                    .buttonStyle(.plain).foregroundStyle(.secondary)
            } else {
                Text(tagName)
                    .font(.system(size: 14))
                    .lineLimit(1)
                    .truncationMode(.middle)
                    .frame(minWidth: 220, maxWidth: .infinity, alignment: .leading)
                    .help(tagName)
                Button { startRename(tagName) } label: {
                    Image(systemName: "pencil").font(.system(size: 11))
                }
                .buttonStyle(.plain).foregroundStyle(.secondary)
                Button(role: .destructive) { deleteTag(tagName) } label: {
                    Image(systemName: "trash").font(.system(size: 11))
                }
                .buttonStyle(.plain).foregroundStyle(.red)
            }
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(.vertical, 10)
    }

    // MARK: - New Tag Row

    private func newTagRow() -> some View {
        HStack(spacing: 10) {
            HStack(spacing: 4) {
                ForEach(TagColor.allIndices, id: \.self) { idx in
                    ColorSwatch(index: idx, isSelected: idx == newTagColorIndex) {
                        newTagColorIndex = idx
                    }
                }
            }
            MacTextField(
                text: $newTagNameText,
                placeholder: tr("tag.newName"),
                onSubmit: { addNewTag() }
            )
            .frame(minWidth: 220, maxWidth: .infinity, minHeight: 24, maxHeight: 24)
            Button(tr("tag.add")) { addNewTag() }
                .buttonStyle(.borderedProminent).controlSize(.small)
            Button(tr("tag.cancel")) { addingNewTag = false; newTagNameText = "" }
                .buttonStyle(.plain).foregroundStyle(.secondary)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(.vertical, 10)
    }

    // MARK: - Actions

    private func startRename(_ name: String) {
        editingTagName = name
        editingTagText = name
    }

    private func commitTagRename(_ oldName: String) {
        let newName = editingTagText.trimmingCharacters(in: .whitespaces)
        guard !newName.isEmpty, newName != oldName else { editingTagName = nil; return }
        TagEditor.renameTag(from: oldName, to: newName)
        tagColors[newName] = tagColors[oldName]
        tagColors.removeValue(forKey: oldName)
        tagCustomColors[newName] = tagCustomColors[oldName]
        tagCustomColors.removeValue(forKey: oldName)
        editingTagName = nil
        onRefresh?()
    }

    /// Add a new tag name+color and persist to the database.
    private func addNewTag() {
        let name = newTagNameText.trimmingCharacters(in: .whitespaces)
        guard !name.isEmpty else { return }
        tagColors[name] = newTagColorIndex
        TagEditor.createTag(name, color: newTagColorIndex)
        addingNewTag = false
        newTagNameText = ""
    }

    private func deleteTag(_ name: String) {
        TagEditor.deleteTagCompletely(name)
        tagColors.removeValue(forKey: name)
        tagCustomColors.removeValue(forKey: name)
        onRefresh?()
    }

    @ViewBuilder
    private func customColorControl(tagName: String, colorIndex: Int) -> some View {
        let isSelected = tagCustomColors[tagName] != nil
        if isCustomColorUnlocked {
            ColorPicker(
                "",
                selection: customColorBinding(tagName: tagName, colorIndex: colorIndex),
                supportsOpacity: false
            )
            .labelsHidden()
            .opacity(0.02)
            .frame(width: 64, height: 24)
            .overlay(
                customColorSwatch(tagName: tagName, colorIndex: colorIndex, isSelected: isSelected)
                    .allowsHitTesting(false)
            )
            .frame(width: 72, alignment: .leading)
            .help(tr("tag.customColor"))
        } else {
            Button(action: onLockedCustomColor) {
                customColorSwatch(tagName: tagName, colorIndex: colorIndex, isSelected: isSelected)
            }
            .buttonStyle(.plain)
            .frame(width: 72, alignment: .leading)
            .help(tr("pro.prompt.customTagColors"))
        }
    }

    private func customColorSwatch(tagName: String, colorIndex: Int, isSelected: Bool) -> some View {
        let fill = Color(nsColor: TagColor.nsColor(for: colorIndex, customColor: tagCustomColors[tagName]))
        return ZStack {
            RoundedRectangle(cornerRadius: 10, style: .continuous)
                .fill(fill)
                .frame(width: 58, height: 18)
                .overlay(
                    RoundedRectangle(cornerRadius: 10, style: .continuous)
                        .stroke(Color.secondary.opacity(0.18), lineWidth: 1)
                )
                .padding(3)
                .overlay(
                    RoundedRectangle(cornerRadius: 13, style: .continuous)
                        .stroke(isSelected ? Color.white : Color.clear, lineWidth: 2)
                )
                .shadow(color: .black.opacity(0.15), radius: 2, y: 1)

            Image(systemName: "crown")
                .font(.system(size: 10, weight: .semibold))
                .symbolRenderingMode(.monochrome)
                .foregroundStyle(Color.white)
                .shadow(color: .black.opacity(0.28), radius: 1, y: 0.5)
        }
    }

    private func customColorBinding(tagName: String, colorIndex: Int) -> Binding<Color> {
        Binding(
            get: {
                Color(nsColor: TagColor.nsColor(for: colorIndex, customColor: tagCustomColors[tagName]))
            },
            set: { color in
                guard isCustomColorUnlocked else {
                    onLockedCustomColor()
                    return
                }
                let nsColor = NSColor(color)
                let customColor = TagCustomColor(nsColor: nsColor)
                guard TagEditor.setCustomColor(customColor, for: tagName) else {
                    onLockedCustomColor()
                    return
                }
                tagCustomColors[tagName] = customColor
                onRefresh?()
            }
        )
    }
}
