import SwiftUI

struct SearchView: View {
    private enum SearchResult: Equatable {
        case idle
        case searching
        case results([Post])
        case noResults
    }
    
    @EnvironmentObject var contentService: ContentService
    @EnvironmentObject var analyticsService: AnalyticsService
    
    @State private var searchIsActive = false
    @State private var searchIsFocused = false
    @State private var searchTerm: String = ""
    @State private var searchResult: SearchResult = .idle
    
    var searchSuggestions: [String] = ["Hackett", "Stromlo", "Northbourne", "Pocock"]
    
    var body: some View {
        ZStack {
            ColorName.background.color()
                .ignoresSafeArea()
            
            if searchIsActive {
                switch searchResult {
                case .idle:
                    VStack(alignment: .leading, spacing: 6) {
                        HStack(alignment: .center, spacing: 0) {
                            Text("Search Suggestions")
                                .textStyle(.headline)
                                .multilineTextAlignment(.leading)
                            
                            Spacer()
                        }
                        .padding(.bottom, 11)
                        .background(VStack() {
                            Spacer()
                            
                            Rectangle()
                                .fill(ColorName.separator.color)
                                .frame(height: 1)
                        })
                        .padding(.top, 16)
                        .padding(.bottom, 10)
                        
                        ForEach(searchSuggestions, id: \.self) { term in
                            Button {
                                searchTerm = term
                            } label: {
                                Text(term)
                                    .textStyle(.body)
                                    .padding(.bottom, 5)
                            }

                        }
                       
                        
                        if !contentService.recentSearchTerms.isEmpty {
                            HStack(alignment: .center, spacing: 0) {
                                Text("Recent Searches")
                                    .textStyle(.headline)
                                    .multilineTextAlignment(.leading)
                                    
                                Spacer()
                            }
                            .padding(.top, 13)
                            .padding(.bottom, 11)
                            .background(VStack() {
                                Spacer()
                                
                                Rectangle()
                                    .fill(ColorName.separator.color)
                                    .frame(height: 1)
                            })
                            .padding(.top, 16)
                            .padding(.bottom, 10)
                            
                            ForEach(contentService.recentSearchTerms, id: \.self) { term in
                                Button {
                                    searchTerm = term
                                } label: {
                                    Text(term)
                                        .textStyle(.body)
                                        .padding(.bottom, 5)
                                }

                            }
                        }
                        
                        Spacer()
                    }
                    .padding()
                    
                    
                case .searching:
                    ProgressView(label: {
                        Text("Searching...")
                            .textStyle(.caption1)
                        }
                    ).progressViewStyle(CircularProgressViewStyle())
                    
                case .results(let posts):
                    ScrollViewWithBanner { _ in
                        PostListingView(posts: posts, showYear: true)
                    }
                    
                case .noResults:
                    Text("No matches found")
                        .textStyle(.subheadline)
                }
                
            } else {
                ScrollView {
                    
                    VStack(alignment: .leading, spacing: 6) {
                        if contentService.topics.isEmpty {
                            Spacer()
                            ProgressView(label: {
                                Text("Loading suggestions...")
                                    .textStyle(.caption1)
                                }
                            ).progressViewStyle(CircularProgressViewStyle())
                            Spacer()
                            
                        } else {
                            HStack {
                                Text("Browse Topics")
                                    .textStyle(.title3)
                                Spacer()
                            }
                            
                            ForEach(contentService.searchFeatureTopics, id: \.self) { topic in
                                SearchFeature(topic: topic)
                                    .padding(.vertical, 7)
                            }
                            
                            ForEach(contentService.topics, id: \.self) { topic in
                                Section {
                                    ForEach(topic.children, id: \.self) { childTopic in
                                        TopicTextNavigation(topic: childTopic)
                                        .padding(.bottom, 5)
                                    }
                                } header: {
                                    TopicHeading(topic: topic)
                                        .padding(.top, 16)
                                        .padding(.bottom, 10)
                                    
                                }
                            }
                        }
                    }
                    .padding()
                }
            }
        }
        .transition(.opacity)
        .animation(.easeInOut, value: searchIsActive)
        .toolbar {
            ToolbarItem(placement: .principal) {
                SearchBar(searchTerm: $searchTerm, isActive: $searchIsActive, isFocused: $searchIsFocused)
            }
        }
        .onDisappear(perform: {
            if searchIsActive, !searchTerm.isEmpty {
                analyticsService.searchResultWasSelected(searchTerm: searchTerm)
                contentService.saveRecentSearchTerm(searchTerm)
            }
        })
        .onChange(of: searchIsActive) { newValue in
            if !newValue {
                searchTerm = ""
                searchResult = .idle
            }
        }
        .onChange(of: searchTerm) { newValue in
            if !newValue.isEmpty {
                Task {
                    searchResult = .searching
                    do {
                        let posts = try await contentService.searchForPosts(newValue)
                        if posts.isEmpty {
                            searchResult = .noResults
                        } else {
                            searchResult = .results(posts)
                        }
                    } catch {
                        if error.localizedDescription != "cancelled" {
                            print(error)
                            searchResult = .idle
                        }
                    }
                }
            } else {
                searchResult = .idle
            }
        }
        .onChange(of: searchResult) { newValue in
            if case .results = newValue {
                searchIsFocused = false
            }
        }
    }
}

struct TopicHeading: View {
    var topic: Topic
    
    var body: some View {
        NavigationLink {
            TopicPostsView(topic: topic)
        } label: {
            HStack(alignment: .center, spacing: 0) {
                ImageName.logo.image
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 22)
                    .foregroundColor(topic.backgroundColor)
                    .padding(.trailing, 10)
                    .padding(.top, 7)
                    .padding(.bottom, 7)
                
                Text(topic.name)
                    .textStyle(.headline, color: ColorName.text.color)
                    .multilineTextAlignment(.leading)
                
                Spacer()
            }
            .padding(.bottom, 5)
            .background(VStack() {
                Spacer()
                
                Rectangle()
                    .fill(topic.backgroundColor)
                    .frame(height: 1)
            })
        }
        .buttonStyle(FlatButtonStyle())
    }
}

struct TopicTextNavigation: View {
    var topic: Topic
    
    var body: some View {
        NavigationLink {
            TopicPostsView(topic: topic)
        } label: {
            Text(topic.name)
                .textStyle(.body)
        }
        .buttonStyle(FlatButtonStyle())
    }
}


struct SearchBar: View {
    @Binding var searchTerm: String
    @Binding var isActive: Bool
    @Binding var isFocused: Bool
    
    var placeholder: String = "Search"
    
    var body: some View {
        HStack(spacing: 0) {
            HStack (spacing: 3) {
                ImageName.System.magnifyingGlass.image
                    .textStyle(.subheadline, color: ColorName.text.color(variation: .tertiary))
                
                LegacyTextField(text: $searchTerm, isFirstResponder: $isFocused) {
                    $0.textColor = ColorName.text.uiColor
                    $0.font = TextStyle.body.uiFont
                    $0.placeholder = placeholder
                    $0.clearButtonMode = .whileEditing
                }
            }
            .padding(.leading, 12)
            .padding(.trailing, 6)
            .padding(.vertical, 0)
            .background(RoundedRectangle(cornerRadius: 6).fill(ColorName.background.color(variation: .secondary)))
            
            if isActive {
                Button {
                    isActive = false
                } label: {
                    Text("Cancel")
                        .textStyle(.headline, color: ColorName.tint.color)
                }
            }
            
        }
        .padding(.horizontal, 10)
        .animation(.easeInOut(duration: 0.25), value: isActive)
        .onChange(of: isFocused) { newValue in
            if newValue {
                isActive = true
            }
        }
        .onChange(of: isActive) { newValue in
            if !newValue {
                isFocused = false
            }
        }
    }
}

struct SearchFeature: View {
    var topic: Topic
    var body: some View {
        VStack(alignment: .leading, spacing: 6) {
            
            TopicLabel(topic: topic)
                .padding(.bottom, 7)
            
            ForEach(topic.featurePosts, id: \.self) { featurePost in
                NavigationLink {
                    PostDetailView(post: featurePost)
                } label: {
                    VStack(alignment: .leading, spacing: 0) {
                        Text(featurePost.title.rendered)
                            .textStyle(.subheadline, color: ColorName.text.color(variation: .primary))
                            .multilineTextAlignment(.leading)
                            .padding(.bottom, 12)
                    
                        Rectangle()
                            .fill(ColorName.background.color)
                            .frame(height: 1)
                    }
                    .padding(.top, 8)
                        
                }
                .buttonStyle(FlatButtonStyle())
            }
            
            NavigationLink {
                TopicPostsView(topic: topic)
            } label: {
                Text("See more...")
                    .textStyle(.subheadline, color: ColorName.tint.color)
                    .multilineTextAlignment(.leading)
                    .padding(.bottom, 6)
                    .padding(.top, 8)
            }
            .buttonStyle(FlatButtonStyle())
            
        }
        .padding(13)
        .background(
            RoundedRectangle(cornerRadius: 6)
                .fill(ColorName.tint.color.opacity(0.05))
                .overlay(
                    RoundedRectangle(cornerRadius: 6)
                        .stroke(ColorName.tint.color.opacity(0.1))
                )
        )
    }
}

struct LegacyTextField: UIViewRepresentable {
    @Binding public var isFirstResponder: Bool
    @Binding public var text: String

    public var configuration = { (view: UITextField) in }

    public init(text: Binding<String>, isFirstResponder: Binding<Bool>, configuration: @escaping (UITextField) -> () = { _ in }) {
        self.configuration = configuration
        self._text = text
        self._isFirstResponder = isFirstResponder
    }

    public func makeUIView(context: Context) -> UITextField {
        let view = UITextField()
        view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        view.addTarget(context.coordinator, action: #selector(Coordinator.textViewDidChange), for: .editingChanged)
        view.delegate = context.coordinator
        return view
    }

    public func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = text
        configuration(uiView)
        switch isFirstResponder {
        case true: uiView.becomeFirstResponder()
        case false: uiView.resignFirstResponder()
        }
    }

    public func makeCoordinator() -> Coordinator {
        Coordinator($text, isFirstResponder: $isFirstResponder)
    }

    public class Coordinator: NSObject, UITextFieldDelegate {
        var text: Binding<String>
        var isFirstResponder: Binding<Bool>

        init(_ text: Binding<String>, isFirstResponder: Binding<Bool>) {
            self.text = text
            self.isFirstResponder = isFirstResponder
        }

        @objc public func textViewDidChange(_ textField: UITextField) {
            self.text.wrappedValue = textField.text ?? ""
        }

        public func textFieldDidBeginEditing(_ textField: UITextField) {
            self.isFirstResponder.wrappedValue = true
        }

        public func textFieldDidEndEditing(_ textField: UITextField) {
            self.isFirstResponder.wrappedValue = false
        }
    }
}

struct SearchView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            SearchView()
        }
    }
}
