import ComposableArchitecture
import SwiftUI

public struct AppStorageMenuView: View {
    @Bindable var store: StoreOf<AppStorageMenuReducer>

    public init(store: StoreOf<AppStorageMenuReducer>) {
        self.store = store
    }

    public var body: some View {
        VStack(spacing: 0) {
            if store.isLoading {
                loadingView
            } else {
                contentView
            }
        }
        .navigationTitle("App Storage Menu")
        .navigationBarTitleDisplayMode(.large)
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button("Refresh") {
                    store.send(.refreshVariables)
                }
            }
        }
        .onAppear {
            store.send(.onAppear)
        }
    }

    @ViewBuilder
    private var loadingView: some View {
        VStack(spacing: 20) {
            ProgressView()
                .scaleEffect(1.2)
            Text("Discovering app storage variables...")
                .font(.headline)
                .foregroundColor(.secondary)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }

    @ViewBuilder
    private var contentView: some View {
        VStack(spacing: 0) {
            // Search bar
            SearchBar(text: $store.searchText.sending(\.searchTextChanged))
                .padding(.horizontal)
                .padding(.bottom, 8)

            // Section filter
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 12) {
                    ForEach(AppStorageMenuReducer.SectionType.allCases) { section in
                        FilterChip(
                            title: section.rawValue,
                            isSelected: store.selectedSection == section,
                            count: countForSection(section)
                        ) {
                            store.send(.sectionSelected(section))
                        }
                    }
                }
                .padding(.horizontal)
            }
            .padding(.bottom, 16)

            // Variables list
            if groupedVariables.isEmpty {
                emptyStateView
            } else {
                variablesList
            }
        }
    }

    @ViewBuilder
    private var emptyStateView: some View {
        VStack(spacing: 16) {
            Image(systemName: store.selectedSection == .all ? "magnifyingglass" : store.selectedSection.iconName)
                .font(.system(size: 48))
                .foregroundColor(.secondary)

            Text("No variables found")
                .font(.headline)

            if !store.searchText.isEmpty {
                Text("Try adjusting your search terms or selecting a different section")
                    .font(.body)
                    .foregroundColor(.secondary)
                    .multilineTextAlignment(.center)
            } else if store.selectedSection != .all {
                Text("No \(store.selectedSection.displayName.lowercased()) found")
                    .font(.body)
                    .foregroundColor(.secondary)
                    .multilineTextAlignment(.center)
            } else {
                Text("No app storage variables discovered")
                    .font(.body)
                    .foregroundColor(.secondary)
                    .multilineTextAlignment(.center)
            }
        }
        .padding(.horizontal, 32)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }

    @ViewBuilder
    private var variablesList: some View {
        ScrollView {
            LazyVStack(spacing: 24, pinnedViews: [.sectionHeaders]) {
                // Group variables by type and display in sections
                ForEach(groupedVariables, id: \.type) { group in
                    Section {
                        LazyVStack(spacing: 12) {
                            ForEach(group.variables) { variable in
                                VariableRow(variable: variable, store: store)
                            }
                        }
                        .padding(.top, 8)
                    } header: {
                        HStack {
                            HStack(spacing: 8) {
                                Image(systemName: group.type.iconName)
                                    .font(.headline)
                                    .foregroundColor(.blue)

                                Text(group.type.displayName)
                                    .font(.title3)
                                    .fontWeight(.semibold)
                                    .foregroundColor(.primary)
                            }

                            Spacer()

                            Text("\(group.variables.count)")
                                .font(.caption)
                                .fontWeight(.medium)
                                .foregroundColor(.secondary)
                                .padding(.horizontal, 8)
                                .padding(.vertical, 4)
                                .background(Color(.systemGray5))
                                .cornerRadius(12)
                        }
                        .padding(.horizontal)
                        .padding(.vertical, 12)
                        .background(
                            Color(.systemGroupedBackground)
                                .overlay(
                                    Rectangle()
                                        .fill(Color(.systemGray4))
                                        .frame(height: 0.5),
                                    alignment: .bottom
                                )
                        )
                    }
                }
            }
            .padding(.horizontal)
            .padding(.bottom, 100) // Extra padding for bottom
        }
    }

    // Group variables by their type for sectioned display
    private var groupedVariables: [VariableGroup] {
        let filteredVars = store.filteredVariables

        // Group by section type
        let grouped = Dictionary(grouping: filteredVars) { variable in
            mapToSectionType(variable.inferredType)
        }

        // If "All" is selected, show all sections; otherwise show only the selected section
        let sectionsToShow: [AppStorageMenuReducer.SectionType]
        if store.selectedSection == .all {
            sectionsToShow = AppStorageMenuReducer.SectionType.allCases.filter { $0 != .all }
        } else {
            sectionsToShow = [store.selectedSection]
        }

        // Convert to sorted array of groups
        return sectionsToShow
            .compactMap { sectionType in
                guard let variables = grouped[sectionType],
                      !variables.isEmpty else { return nil }

                return VariableGroup(
                    type: sectionType,
                    variables: variables.sorted { $0.name < $1.name }
                )
            }
    }

    private func mapToSectionType(_ type: AppStorageVariable.AppStorageType) -> AppStorageMenuReducer.SectionType {
        switch type {
        case .boolean: return .booleans
        case .integer, .double, .timeInterval: return .numbers
        case .string: return .strings
        case .stringArray: return .arrays
        case .date: return .dates
        case .enumType: return .enums
        case .unknown: return .strings // Default unknown to strings section
        }
    }

    private func countForSection(_ section: AppStorageMenuReducer.SectionType) -> Int {
        if section == .all {
            return store.discoveredVariables.count
        }

        return store.discoveredVariables.filter { variable in
            switch section {
            case .booleans: return variable.inferredType == .boolean
            case .numbers: return [.integer, .double, .timeInterval].contains(variable.inferredType)
            case .strings: return variable.inferredType == .string
            case .arrays: return variable.inferredType == .stringArray
            case .dates: return variable.inferredType == .date
            case .enums: return variable.inferredType == .enumType
            case .all: return true
            }
        }.count
    }
}

// MARK: - Helper Views

struct VariableGroup {
    let type: AppStorageMenuReducer.SectionType
    let variables: [AppStorageVariable]
}

struct SearchBar: View {
    @Binding var text: String

    var body: some View {
        HStack {
            Image(systemName: "magnifyingglass")
                .foregroundColor(.secondary)

            TextField("Search variables...", text: $text)
                .textFieldStyle(PlainTextFieldStyle())

            if !text.isEmpty {
                Button("Clear") {
                    text = ""
                }
                .font(.caption)
                .foregroundColor(.blue)
            }
        }
        .padding(.horizontal, 12)
        .padding(.vertical, 8)
        .background(Color(.systemGray6))
        .cornerRadius(10)
    }
}

struct FilterChip: View {
    let title: String
    let isSelected: Bool
    let count: Int
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            HStack(spacing: 4) {
                Text(title)
                    .font(.caption)
                    .fontWeight(isSelected ? .semibold : .medium)

                Text("(\(count))")
                    .font(.caption2)
                    .opacity(0.7)
            }
            .padding(.horizontal, 12)
            .padding(.vertical, 6)
            .background(isSelected ? Color.blue : Color(.systemGray5))
            .foregroundColor(isSelected ? .white : .primary)
            .cornerRadius(16)
        }
        .buttonStyle(PlainButtonStyle())
    }
}

struct VariableRow: View {
    let variable: AppStorageVariable
    let store: StoreOf<AppStorageMenuReducer>

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            // Header
            VStack(alignment: .leading, spacing: 4) {
                Text(variable.name)
                    .font(.headline)

                if let description = variable.description {
                    Text(description)
                        .font(.caption)
                        .foregroundColor(.secondary)
                        .padding(.bottom, 2)
                }

                HStack {
                    Text("Key: \(variable.keyName)")
                        .font(.caption)
                        .foregroundColor(.secondary)

                    Spacer()

                    Text(variable.inferredType.rawValue)
                        .font(.caption2)
                        .padding(.horizontal, 6)
                        .padding(.vertical, 2)
                        .background(Color(.systemGray5))
                        .cornerRadius(4)
                }
            }

            // Control based on type
            controlForVariable(variable)
        }
        .padding()
        .background(Color(.systemGroupedBackground))
        .cornerRadius(12)
    }

    @ViewBuilder
    private func controlForVariable(_ variable: AppStorageVariable) -> some View {
        switch variable.currentValue {
        case .boolean(let value):
            BooleanControl(
                currentValue: value,
                onToggle: { newValue in
                    store.send(.updateVariable(id: variable.id, value: .boolean(newValue)))
                }
            )

        case .integer(let value):
            IntegerControl(
                currentValue: value,
                onUpdate: { newValue in
                    store.send(.updateVariable(id: variable.id, value: .integer(newValue)))
                }
            )

        case .string(let value):
            StringControl(
                currentValue: value,
                onUpdate: { newValue in
                    store.send(.updateVariable(id: variable.id, value: .string(newValue)))
                }
            )

        case .enumType(let selectedCase, let allCases, let enumTypeName):
            EnumControl(
                currentCase: selectedCase,
                allCases: allCases,
                enumTypeName: enumTypeName,
                onUpdate: { newValue in
                    store.send(.updateVariable(id: variable.id, value: .enumType(selectedCase: newValue, allCases: allCases, enumTypeName: enumTypeName)))
                }
            )

        case .stringArray(let array):
            StringArrayControl(
                currentArray: array,
                onAdd: { newValue in
                    var newArray = array
                    newArray.append(newValue)
                    store.send(.updateVariable(id: variable.id, value: .stringArray(newArray)))
                },
                onRemove: { index in
                    var newArray = array
                    if index < newArray.count {
                        newArray.remove(at: index)
                    }
                    store.send(.updateVariable(id: variable.id, value: .stringArray(newArray)))
                },
                onClear: {
                    store.send(.updateVariable(id: variable.id, value: .stringArray([])))
                }
            )

        case .date(let date):
            DateControl(
                currentDate: date,
                onSetToNow: {
                    store.send(.updateVariable(id: variable.id, value: .date(Date())))
                },
                onClear: {
                    store.send(.updateVariable(id: variable.id, value: .date(nil)))
                }
            )

        case .timeInterval(let interval):
            TimeIntervalControl(
                currentValue: interval,
                onUpdate: { newValue in
                    store.send(.updateVariable(id: variable.id, value: .timeInterval(newValue)))
                }
            )

        case .double(let value):
            DoubleControl(
                currentValue: value,
                onUpdate: { newValue in
                    store.send(.updateVariable(id: variable.id, value: .double(newValue)))
                }
            )

        case .unknown(let value):
            UnknownControl(value: value)
        }
    }
}

// MARK: - Control Components

struct BooleanControl: View {
    let currentValue: Bool
    let onToggle: (Bool) -> Void

    var body: some View {
        HStack {
            Text("Current: \(currentValue ? "true" : "false")")
                .font(.body)

            Spacer()

            Toggle("", isOn: .init(
                get: { currentValue },
                set: onToggle
            ))
            .labelsHidden()
        }
    }
}

struct EnumControl: View {
    let currentCase: String
    let allCases: [String]
    let enumTypeName: String
    let onUpdate: (String) -> Void

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            VStack(alignment: .leading, spacing: 4) {
                Text("Current: \(enumTypeName).\(currentCase)")
                    .font(.body)
                Text("Available cases: \(allCases.count)")
                    .font(.caption)
                    .foregroundColor(.secondary)
            }

            // Case selection
            LazyVGrid(columns: [
                GridItem(.flexible()),
                GridItem(.flexible()),
            ], spacing: 8) {
                ForEach(allCases, id: \.self) { enumCase in
                    Button(action: {
                        onUpdate(enumCase)
                    }) {
                        HStack {
                            Image(systemName: currentCase == enumCase ? "checkmark.circle.fill" : "circle")
                                .foregroundColor(currentCase == enumCase ? .blue : .secondary)

                            Text(".\(enumCase)")
                                .font(.caption)
                                .foregroundColor(currentCase == enumCase ? .blue : .primary)
                                .lineLimit(1)

                            Spacer()
                        }
                        .padding(.horizontal, 12)
                        .padding(.vertical, 8)
                        .background(
                            RoundedRectangle(cornerRadius: 8)
                                .fill(currentCase == enumCase ? Color.blue.opacity(0.1) : Color(.systemGray6))
                                .overlay(
                                    RoundedRectangle(cornerRadius: 8)
                                        .stroke(currentCase == enumCase ? Color.blue : Color.clear, lineWidth: 1)
                                )
                        )
                    }
                    .buttonStyle(PlainButtonStyle())
                }
            }
        }
    }
}

struct IntegerControl: View {
    let currentValue: Int
    let onUpdate: (Int) -> Void
    @State private var editingValue: String = ""
    @State private var isEditing = false

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            if isEditing {
                HStack {
                    TextField("Enter number", text: $editingValue)
                        .keyboardType(.numberPad)
                        .textFieldStyle(RoundedBorderTextFieldStyle())

                    Button("Save") {
                        if let newValue = Int(editingValue) {
                            onUpdate(newValue)
                        }
                        isEditing = false
                    }
                    .buttonStyle(.borderedProminent)

                    Button("Cancel") {
                        isEditing = false
                        editingValue = String(currentValue)
                    }
                    .buttonStyle(.bordered)
                }
            } else {
                HStack {
                    Text("Current: \(currentValue)")
                        .font(.body)

                    Spacer()

                    HStack {
                        Button("-") {
                            if currentValue > 0 {
                                onUpdate(currentValue - 1)
                            }
                        }
                        .frame(width: 32, height: 32)
                        .background(Color.blue)
                        .foregroundColor(.white)
                        .cornerRadius(16)

                        Button("Edit") {
                            editingValue = String(currentValue)
                            isEditing = true
                        }
                        .buttonStyle(.bordered)

                        Button("+") {
                            onUpdate(currentValue + 1)
                        }
                        .frame(width: 32, height: 32)
                        .background(Color.blue)
                        .foregroundColor(.white)
                        .cornerRadius(16)
                    }
                }
            }
        }
        .onAppear {
            editingValue = String(currentValue)
        }
    }
}

struct StringControl: View {
    let currentValue: String
    let onUpdate: (String) -> Void
    @State private var editingValue: String = ""
    @State private var isEditing = false

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            if isEditing {
                VStack(spacing: 8) {
                    TextField("Enter text", text: $editingValue)
                        .textFieldStyle(RoundedBorderTextFieldStyle())

                    HStack {
                        Button("Cancel") {
                            isEditing = false
                            editingValue = currentValue
                        }
                        .buttonStyle(.bordered)

                        Button("Save") {
                            onUpdate(editingValue)
                            isEditing = false
                        }
                        .buttonStyle(.borderedProminent)
                    }
                }
            } else {
                VStack(alignment: .leading, spacing: 4) {
                    Text("Current: \(currentValue.isEmpty ? "(empty)" : currentValue)")
                        .font(.body)
                        .foregroundColor(currentValue.isEmpty ? .secondary : .primary)

                    Button("Edit") {
                        editingValue = currentValue
                        isEditing = true
                    }
                    .buttonStyle(.bordered)
                }
            }
        }
        .onAppear {
            editingValue = currentValue
        }
    }
}

struct StringArrayControl: View {
    let currentArray: [String]
    let onAdd: (String) -> Void
    let onRemove: (Int) -> Void
    let onClear: () -> Void
    @State private var newItem = ""
    @State private var isAdding = false

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack {
                Text("Items: \(currentArray.count)")
                    .font(.body)

                Spacer()

                if !currentArray.isEmpty {
                    Button("Clear All") {
                        onClear()
                    }
                    .buttonStyle(.bordered)
                    .foregroundColor(.red)
                }

                Button("Add") {
                    isAdding = true
                }
                .buttonStyle(.bordered)
            }

            if isAdding {
                VStack(spacing: 8) {
                    TextField("Enter new item", text: $newItem)
                        .textFieldStyle(RoundedBorderTextFieldStyle())

                    HStack {
                        Button("Cancel") {
                            isAdding = false
                            newItem = ""
                        }
                        .buttonStyle(.bordered)

                        Button("Add") {
                            if !newItem.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
                                onAdd(newItem)
                                newItem = ""
                                isAdding = false
                            }
                        }
                        .buttonStyle(.borderedProminent)
                        .disabled(newItem.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
                    }
                }
            }

            if currentArray.isEmpty {
                Text("No items")
                    .font(.body)
                    .foregroundColor(.secondary)
                    .italic()
            } else {
                ForEach(Array(currentArray.enumerated()), id: \.offset) { index, item in
                    HStack {
                        VStack(alignment: .leading, spacing: 2) {
                            Text("[\(index)]")
                                .font(.caption2)
                                .foregroundColor(.secondary)
                            Text(item)
                                .font(.caption)
                        }

                        Spacer()

                        Button("Remove") {
                            onRemove(index)
                        }
                        .font(.caption)
                        .foregroundColor(.red)
                    }
                    .padding(.vertical, 2)
                }
            }
        }
    }
}

struct DateControl: View {
    let currentDate: Date?
    let onSetToNow: () -> Void
    let onClear: () -> Void

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            if let date = currentDate {
                VStack(alignment: .leading, spacing: 4) {
                    Text("Current: \(date.formatted(date: .abbreviated, time: .shortened))")
                        .font(.body)
                    Text("Timestamp: \(date.timeIntervalSince1970, specifier: "%.0f")")
                        .font(.caption)
                        .foregroundColor(.secondary)
                }
            } else {
                Text("Current: nil")
                    .font(.body)
                    .foregroundColor(.secondary)
            }

            HStack {
                Button("Set to Now") {
                    onSetToNow()
                }
                .buttonStyle(.bordered)

                Button("Clear") {
                    onClear()
                }
                .buttonStyle(.bordered)
                .foregroundColor(.red)
            }
        }
    }
}

struct TimeIntervalControl: View {
    let currentValue: TimeInterval
    let onUpdate: (TimeInterval) -> Void

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            Text("Current: \(currentValue, specifier: "%.0f") seconds")
                .font(.body)

            HStack {
                Button("Set to Now") {
                    onUpdate(Date().timeIntervalSince1970)
                }
                .buttonStyle(.bordered)

                Button("Reset to 0") {
                    onUpdate(0)
                }
                .buttonStyle(.bordered)
            }
        }
    }
}

struct DoubleControl: View {
    let currentValue: Double
    let onUpdate: (Double) -> Void
    @State private var editingValue: String = ""
    @State private var isEditing = false

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            if isEditing {
                HStack {
                    TextField("Enter number", text: $editingValue)
                        .keyboardType(.decimalPad)
                        .textFieldStyle(RoundedBorderTextFieldStyle())

                    Button("Save") {
                        if let newValue = Double(editingValue) {
                            onUpdate(newValue)
                        }
                        isEditing = false
                    }
                    .buttonStyle(.borderedProminent)

                    Button("Cancel") {
                        isEditing = false
                        editingValue = String(currentValue)
                    }
                    .buttonStyle(.bordered)
                }
            } else {
                HStack {
                    Text("Current: \(currentValue, specifier: "%.2f")")
                        .font(.body)

                    Spacer()

                    Button("Edit") {
                        editingValue = String(currentValue)
                        isEditing = true
                    }
                    .buttonStyle(.bordered)
                }
            }
        }
        .onAppear {
            editingValue = String(currentValue)
        }
    }
}

struct UnknownControl: View {
    let value: String

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text("Unknown Type")
                .font(.body)
                .foregroundColor(.orange)
            Text("Value: \(value)")
                .font(.caption)
                .foregroundColor(.secondary)
            Text("This variable type is not currently supported for editing")
                .font(.caption2)
                .foregroundColor(.secondary)
                .italic()
        }
    }
}

#Preview {
    AppStorageMenuView(store: Store(initialState: AppStorageMenuReducer.State()) {
        AppStorageMenuReducer()
    })
}
