import PhotosUI
import SwiftUI

struct AddEditProblemView: View {
    let problemId: UUID?
    let gymId: UUID?
    @EnvironmentObject var dataManager: ClimbingDataManager
    @EnvironmentObject var themeManager: ThemeManager
    @Environment(\.dismiss) private var dismiss

    @State private var selectedGym: Gym?
    @State private var name = ""
    @State private var description = ""
    @State private var selectedClimbType: ClimbType = .boulder
    @State private var selectedDifficultySystem: DifficultySystem = .vScale
    @State private var difficultyGrade = ""
    @State private var location = ""
    @State private var tags = ""
    @State private var notes = ""
    @State private var isActive = true
    @State private var dateSet = Date()
    @State private var imagePaths: [String] = []
    @State private var selectedPhotos: [PhotosPickerItem] = []
    @State private var imageData: [Data] = []
    @State private var isEditing = false
    enum SheetType: Identifiable {
        case photoOptions

        var id: Int {
            switch self {
            case .photoOptions: return 0
            }
        }
    }

    @State private var activeSheet: SheetType?
    @State private var showCamera = false
    @State private var showPhotoPicker = false
    @State private var isPhotoPickerActionPending = false
    @State private var isCameraActionPending = false

    private var existingProblem: Problem? {
        guard let problemId = problemId else { return nil }
        return dataManager.problem(withId: problemId)
    }

    private var availableClimbTypes: [ClimbType] {
        selectedGym?.supportedClimbTypes ?? ClimbType.allCases
    }

    var availableDifficultySystems: [DifficultySystem] {
        guard let gym = selectedGym else {
            return DifficultySystem.systemsForClimbType(selectedClimbType)
        }

        let compatibleSystems = DifficultySystem.systemsForClimbType(selectedClimbType)
        let gymSupportedSystems = gym.difficultySystems.filter { system in
            compatibleSystems.contains(system)
        }

        return gymSupportedSystems.isEmpty ? compatibleSystems : gymSupportedSystems
    }

    private var availableGrades: [String] {
        selectedDifficultySystem.availableGrades
    }

    init(problemId: UUID? = nil, gymId: UUID? = nil) {
        self.problemId = problemId
        self.gymId = gymId
    }

    var body: some View {
        NavigationStack {
            Form {
                GymSelectionSection()
                BasicInfoSection()
                PhotosSection()
                ClimbTypeSection()
                DifficultySection()
                LocationSection()
                TagsSection()
                AdditionalInfoSection()
            }
            .navigationTitle(isEditing ? "Edit Problem" : "Add Problem")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cancel") {
                        dismiss()
                    }
                }

                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Save") {
                        saveProblem()
                    }
                    .disabled(!canSave)
                }
            }
        }
        .onAppear {
            loadExistingProblem()
            setupInitialGym()
        }
        .onChange(of: dataManager.gyms) {
            if selectedGym == nil && !dataManager.gyms.isEmpty {
                selectedGym = dataManager.gyms.first
            }
        }
        .onChange(of: selectedGym) {
            updateAvailableOptions()
        }
        .onChange(of: selectedClimbType) {
            updateDifficultySystem()
        }
        .onChange(of: selectedDifficultySystem) {
            resetGradeIfNeeded()
        }
        .sheet(
            item: $activeSheet,
            onDismiss: {
                if isCameraActionPending {
                    showCamera = true
                    isCameraActionPending = false
                    return
                }
                if isPhotoPickerActionPending {
                    showPhotoPicker = true
                    isPhotoPickerActionPending = false
                }
            }
        ) { sheetType in
            switch sheetType {
            case .photoOptions:
                PhotoOptionSheet(
                    selectedPhotos: $selectedPhotos,
                    imageData: $imageData,
                    maxImages: 5,
                    onCameraSelected: {
                        isCameraActionPending = true
                        activeSheet = nil
                    },
                    onPhotoLibrarySelected: {
                        isPhotoPickerActionPending = true
                    },
                    onDismiss: {
                        activeSheet = nil
                    }
                )
            }
        }
        .fullScreenCover(isPresented: $showCamera) {
            CameraImagePicker { capturedImage in
                if let jpegData = capturedImage.jpegData(compressionQuality: 0.8) {
                    imageData.append(jpegData)
                }
            }
        }
        .photosPicker(
            isPresented: $showPhotoPicker,
            selection: $selectedPhotos,
            maxSelectionCount: 5 - imageData.count,
            matching: .images
        )
        .onChange(of: selectedPhotos) {
            Task {
                await loadSelectedPhotos()
            }
        }
    }

    @ViewBuilder
    private func GymSelectionSection() -> some View {
        Section("Select Gym") {
            if dataManager.gyms.isEmpty {
                Text("No gyms available. Add a gym first.")
                    .foregroundColor(.secondary)
            } else {
                ForEach(dataManager.gyms, id: \.id) { gym in
                    HStack {
                        VStack(alignment: .leading, spacing: 4) {
                            Text(gym.name)
                                .font(.headline)

                            if let location = gym.location, !location.isEmpty {
                                Text(location)
                                    .font(.caption)
                                    .foregroundColor(.secondary)
                            }
                        }

                        Spacer()

                        if selectedGym?.id == gym.id {
                            Image(systemName: "checkmark.circle.fill")
                                .foregroundColor(themeManager.accentColor)
                        }
                    }
                    .contentShape(Rectangle())
                    .onTapGesture {
                        selectedGym = gym
                    }
                }
            }
        }
    }

    @ViewBuilder
    private func BasicInfoSection() -> some View {
        Section("Problem Details") {
            TextField("Problem Name (Optional)", text: $name)

            VStack(alignment: .leading, spacing: 8) {
                Text("Description (Optional)")
                    .font(.headline)

                TextEditor(text: $description)
                    .frame(minHeight: 80)
                    .padding(8)
                    .background(
                        RoundedRectangle(cornerRadius: 8)
                            .fill(.quaternary)
                    )
            }
        }
    }

    @ViewBuilder
    private func ClimbTypeSection() -> some View {
        if selectedGym != nil {
            Section("Climb Type") {
                ForEach(availableClimbTypes, id: \.self) { climbType in
                    HStack {
                        Text(climbType.displayName)
                        Spacer()
                        if selectedClimbType == climbType {
                            Image(systemName: "checkmark.circle.fill")
                                .foregroundColor(themeManager.accentColor)
                        } else {
                            Image(systemName: "circle")
                                .foregroundColor(.gray)
                        }
                    }
                    .contentShape(Rectangle())
                    .onTapGesture {
                        selectedClimbType = climbType
                    }
                }
            }
        }
    }

    @ViewBuilder
    private func DifficultySection() -> some View {
        Section("Difficulty") {
            // Difficulty System
            VStack(alignment: .leading, spacing: 8) {
                Text("Difficulty System")
                    .font(.headline)

                ForEach(availableDifficultySystems, id: \.self) { system in
                    HStack {
                        Text(system.displayName)
                        Spacer()
                        if selectedDifficultySystem == system {
                            Image(systemName: "checkmark.circle.fill")
                                .foregroundColor(themeManager.accentColor)
                        } else {
                            Image(systemName: "circle")
                                .foregroundColor(.gray)
                        }
                    }
                    .contentShape(Rectangle())
                    .onTapGesture {
                        selectedDifficultySystem = system
                    }
                }
            }

            // Grade Selection
            VStack(alignment: .leading, spacing: 8) {
                Text("Grade (Required)")
                    .font(.headline)

                if selectedDifficultySystem == .custom || availableGrades.isEmpty {
                    TextField("Enter custom grade (numbers only)", text: $difficultyGrade)
                        .textFieldStyle(.roundedBorder)
                        .keyboardType(.numberPad)
                        .onChange(of: difficultyGrade) {
                            // Filter out non-numeric characters
                            difficultyGrade = difficultyGrade.filter { $0.isNumber }
                        }
                } else {
                    Menu {
                        if !difficultyGrade.isEmpty {
                            Button("Clear Selection") {
                                difficultyGrade = ""
                            }

                            Divider()
                        }

                        ForEach(availableGrades, id: \.self) { grade in
                            Button(grade) {
                                difficultyGrade = grade
                            }
                        }
                    } label: {
                        HStack {
                            Text(difficultyGrade.isEmpty ? "Select Grade" : difficultyGrade)
                                .foregroundColor(difficultyGrade.isEmpty ? .secondary : .primary)
                                .fontWeight(difficultyGrade.isEmpty ? .regular : .semibold)

                            Spacer()

                            Image(systemName: "chevron.down")
                                .foregroundColor(.secondary)
                                .font(.caption)
                        }
                        .padding()
                        .background(
                            RoundedRectangle(cornerRadius: 8)
                                .fill(.gray.opacity(0.1))
                                .stroke(
                                    difficultyGrade.isEmpty
                                        ? .red.opacity(0.5) : .gray.opacity(0.3), lineWidth: 1)
                        )
                    }
                    .buttonStyle(.plain)
                }

                if difficultyGrade.isEmpty {
                    Text("Please select a grade to continue")
                        .font(.caption)
                        .foregroundColor(.red)
                        .italic()
                } else {
                    Text("Selected: \(difficultyGrade)")
                        .font(.caption)
                        .foregroundColor(themeManager.accentColor)
                }
            }
        }
    }

    @ViewBuilder
    private func LocationSection() -> some View {
        Section("Location & Details") {
            TextField(
                "Location (Optional)", text: $location, prompt: Text("e.g., 'Cave area', 'Wall 3'"))

            DatePicker(
                "Date Set",
                selection: $dateSet,
                displayedComponents: [.date]
            )
        }
    }

    @ViewBuilder
    private func TagsSection() -> some View {
        Section("Tags (Optional)") {
            TextField("Tags", text: $tags, prompt: Text("e.g., crimpy, dynamic (comma-separated)"))
        }
    }

    @ViewBuilder
    private func PhotosSection() -> some View {
        Section("Photos (Optional)") {
            Button(action: {
                activeSheet = .photoOptions
            }) {
                HStack {
                    Image(systemName: "camera.fill")
                        .foregroundColor(themeManager.accentColor)
                        .font(.title2)
                    VStack(alignment: .leading, spacing: 2) {
                        Text("Add Photos")
                            .font(.headline)
                            .foregroundColor(themeManager.accentColor)
                        Text("\(imageData.count) of 5 photos added")
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }
                    Spacer()
                    Image(systemName: "chevron.right")
                        .foregroundColor(.secondary)
                        .font(.caption)
                }
                .padding(.vertical, 4)
            }
            .disabled(imageData.count >= 5)

            if !imageData.isEmpty {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 12) {
                        ForEach(imageData.indices, id: \.self) { index in
                            if let uiImage = UIImage(data: imageData[index]) {
                                ZStack(alignment: .topTrailing) {
                                    Image(uiImage: uiImage)
                                        .resizable()
                                        .aspectRatio(contentMode: .fill)
                                        .frame(width: 80, height: 80)
                                        .clipped()
                                        .cornerRadius(8)

                                    Button(action: {
                                        imageData.remove(at: index)
                                        if index < imagePaths.count {
                                            imagePaths.remove(at: index)
                                        }
                                    }) {
                                        Image(systemName: "xmark.circle.fill")
                                            .foregroundColor(.red)
                                            .background(Circle().fill(.white))
                                            .font(.system(size: 18))
                                    }
                                    .offset(x: 4, y: -4)
                                }
                                .frame(width: 88, height: 88)  // Extra space for button
                            } else {
                                RoundedRectangle(cornerRadius: 8)
                                    .fill(.gray.opacity(0.3))
                                    .frame(width: 80, height: 80)
                                    .overlay {
                                        Image(systemName: "photo")
                                            .foregroundColor(.gray)
                                    }
                            }
                        }
                    }
                    .padding(.horizontal, 1)
                    .padding(.vertical, 8)
                }
            }
        }
    }

    @ViewBuilder
    private func AdditionalInfoSection() -> some View {
        Section("Additional Information") {
            VStack(alignment: .leading, spacing: 8) {
                Text("Notes (Optional)")
                    .font(.headline)

                TextEditor(text: $notes)
                    .frame(minHeight: 80)
                    .padding(8)
                    .background(
                        RoundedRectangle(cornerRadius: 8)
                            .fill(.quaternary)
                    )
            }

            Toggle("Problem is currently active", isOn: $isActive)
        }
    }

    private var canSave: Bool {
        selectedGym != nil
            && !difficultyGrade.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
    }

    private func setupInitialGym() {
        if let gymId = gymId {
            selectedGym = dataManager.gym(withId: gymId)
        }

        // Always ensure a gym is selected if available and none is currently selected
        if selectedGym == nil && !dataManager.gyms.isEmpty {
            selectedGym = dataManager.gyms.first
        }
    }

    private func loadExistingProblem() {
        if let problem = existingProblem {
            isEditing = true
            selectedGym = dataManager.gym(withId: problem.gymId)
            name = problem.name ?? ""
            description = problem.description ?? ""
            selectedClimbType = problem.climbType
            selectedDifficultySystem = problem.difficulty.system
            difficultyGrade = problem.difficulty.grade

            location = problem.location ?? ""
            tags = problem.tags.joined(separator: ", ")
            notes = problem.notes ?? ""
            isActive = problem.isActive
            imagePaths = problem.imagePaths

            // Load image data for preview
            imageData = []
            for imagePath in problem.imagePaths {
                if let data = ImageManager.shared.loadImageData(fromPath: imagePath) {
                    imageData.append(data)
                }
            }

            if let dateSet = problem.dateSet {
                self.dateSet = dateSet
            }
        }
    }

    private func updateAvailableOptions() {
        guard let gym = selectedGym else { return }

        // Auto-select climb type if there's only one available
        if gym.supportedClimbTypes.count == 1, selectedClimbType != gym.supportedClimbTypes.first! {
            selectedClimbType = gym.supportedClimbTypes.first!
        }

        updateDifficultySystem()
    }

    private func updateDifficultySystem() {
        let available = availableDifficultySystems

        if !available.contains(selectedDifficultySystem) {
            selectedDifficultySystem = available.first ?? .custom
        }

        if available.count == 1, selectedDifficultySystem != available.first! {
            selectedDifficultySystem = available.first!
        }
    }

    private func resetGradeIfNeeded() {
        let availableGrades = selectedDifficultySystem.availableGrades
        if !availableGrades.isEmpty && !availableGrades.contains(difficultyGrade) {
            difficultyGrade = ""
        }
    }

    private func loadSelectedPhotos() async {
        for item in selectedPhotos {
            if let data = try? await item.loadTransferable(type: Data.self) {
                imageData.append(data)
            }
        }
        selectedPhotos.removeAll()
    }

    private func saveProblem() {
        guard let gym = selectedGym, canSave else { return }

        let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
        let trimmedDescription = description.trimmingCharacters(in: .whitespacesAndNewlines)

        let trimmedLocation = location.trimmingCharacters(in: .whitespacesAndNewlines)
        let trimmedNotes = notes.trimmingCharacters(in: .whitespacesAndNewlines)
        let trimmedTags = tags.split(separator: ",").map {
            $0.trimmingCharacters(in: .whitespacesAndNewlines)
        }.filter { !$0.isEmpty }

        let difficulty = DifficultyGrade(system: selectedDifficultySystem, grade: difficultyGrade)

        if isEditing, let problem = existingProblem {
            var allImagePaths = imagePaths

            let newImagesStartIndex = imagePaths.count
            if imageData.count > newImagesStartIndex {
                for i in newImagesStartIndex..<imageData.count {
                    let data = imageData[i]
                    let imageIndex = allImagePaths.count
                    let deterministicName = ImageNamingUtils.generateImageFilename(
                        problemId: problem.id.uuidString, imageIndex: imageIndex)

                    if let relativePath = ImageManager.shared.saveImageData(
                        data, withName: deterministicName)
                    {
                        allImagePaths.append(relativePath)
                    }
                }
            }

            let updatedProblem = problem.updated(
                name: trimmedName.isEmpty ? nil : trimmedName,
                description: trimmedDescription.isEmpty ? nil : trimmedDescription,
                climbType: selectedClimbType,
                difficulty: difficulty,

                tags: trimmedTags,
                location: trimmedLocation.isEmpty ? nil : trimmedLocation,
                imagePaths: allImagePaths,
                isActive: isActive,
                dateSet: dateSet,
                notes: trimmedNotes.isEmpty ? nil : trimmedNotes
            )
            dataManager.updateProblem(updatedProblem)
        } else {
            let newProblem = Problem(
                gymId: gym.id,
                name: trimmedName.isEmpty ? nil : trimmedName,
                description: trimmedDescription.isEmpty ? nil : trimmedDescription,
                climbType: selectedClimbType,
                difficulty: difficulty,

                tags: trimmedTags,
                location: trimmedLocation.isEmpty ? nil : trimmedLocation,
                imagePaths: [],
                dateSet: dateSet,
                notes: trimmedNotes.isEmpty ? nil : trimmedNotes
            )

            dataManager.addProblem(newProblem)

            if !imageData.isEmpty {
                var imagePaths: [String] = []

                for (index, data) in imageData.enumerated() {
                    let deterministicName = ImageNamingUtils.generateImageFilename(
                        problemId: newProblem.id.uuidString, imageIndex: index)

                    if let relativePath = ImageManager.shared.saveImageData(
                        data, withName: deterministicName)
                    {
                        imagePaths.append(relativePath)
                    }
                }

                if !imagePaths.isEmpty {
                    let updatedProblem = newProblem.updated(imagePaths: imagePaths)
                    dataManager.updateProblem(updatedProblem)
                }
            }
        }

        dismiss()
    }
}

#Preview {
    AddEditProblemView()
        .environmentObject(ClimbingDataManager.preview)
}
