import MarkdownUI
import SwiftUI

struct SybilSearchResultsView: View {
    var search: SearchDetail?
    var isLoading: Bool
    var isRunning: Bool
    var isStartingChat: Bool = false
    var topContentInset: CGFloat = 0
    var bottomContentInset: CGFloat = 0
    var onStartChat: (() -> Void)? = nil

    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 16) {
                if let query = search?.query, !query.isEmpty {
                    VStack(alignment: .leading, spacing: 12) {
                        VStack(alignment: .leading, spacing: 4) {
                            Text("Results for")
                                .font(.sybil(.footnote))
                                .foregroundStyle(SybilTheme.textMuted)
                            Text(query)
                                .font(.sybil(.title3, weight: .semibold))
                                .foregroundStyle(SybilTheme.text)
                                .fixedSize(horizontal: false, vertical: true)

                            Text(resultCountLabel)
                                .font(.sybil(.caption))
                                .foregroundStyle(SybilTheme.textMuted)
                        }

                        if let onStartChat {
                            Button {
                                onStartChat()
                            } label: {
                                HStack(spacing: 8) {
                                    if isStartingChat {
                                        ProgressView()
                                            .controlSize(.small)
                                            .tint(SybilTheme.text)
                                    } else {
                                        Image(systemName: "bubble.left.and.text.bubble.right")
                                            .font(.system(size: 14, weight: .semibold))
                                    }
                                    Text(isStartingChat ? "Starting chat..." : "Chat with results")
                                        .font(.sybil(.caption, weight: .semibold))
                                }
                                .foregroundStyle(SybilTheme.text)
                                .padding(.horizontal, 12)
                                .padding(.vertical, 9)
                                .background(
                                    RoundedRectangle(cornerRadius: 10)
                                        .fill(SybilTheme.primary.opacity(0.14))
                                        .overlay(
                                            RoundedRectangle(cornerRadius: 10)
                                                .stroke(SybilTheme.primary.opacity(0.30), lineWidth: 1)
                                        )
                                )
                            }
                            .buttonStyle(.plain)
                            .disabled(!canStartChat)
                            .opacity(canStartChat ? 1 : 0.55)
                        }
                    }
                }

                if isRunning || (search?.answerText?.isEmpty == false) || (search?.answerError?.isEmpty == false) {
                    answerCard
                        .frame(maxWidth: .infinity, alignment: .leading)
                }

                if (isLoading || isRunning) && (search?.results.isEmpty ?? true) {
                    HStack(spacing: 8) {
                        ProgressView()
                            .controlSize(.small)
                            .tint(SybilTheme.textMuted)
                        Text(isRunning ? "Searching Exa…" : "Loading search…")
                            .font(.sybil(.footnote))
                            .foregroundStyle(SybilTheme.textMuted)
                    }
                }

                if !isLoading, !isRunning, let search, !search.query.orEmpty.isEmpty, search.results.isEmpty {
                    Text("No results found.")
                        .font(.sybil(.footnote))
                        .foregroundStyle(SybilTheme.textMuted)
                }

                ForEach(search?.results ?? []) { result in
                    SearchResultCard(result: result)
                        .accessibilityLabel("SearchResultCard")
                        .frame(maxWidth: .infinity, alignment: .leading)
                }

                if let error = search?.error, !error.isEmpty {
                    Text(error)
                        .font(.sybil(.footnote))
                        .foregroundStyle(SybilTheme.danger)
                }
            }
            .frame(maxWidth: SybilLayout.webContentMaxWidth, alignment: .leading)
            .frame(maxWidth: .infinity, alignment: .center)
            .padding(.horizontal, 14)
            .padding(.top, 20 + topContentInset)
            .padding(.bottom, 20 + bottomContentInset)
        }
        .scrollDismissesKeyboard(.interactively)
        .frame(maxWidth: .infinity, alignment: .leading)
    }

    private var resultCountLabel: String {
        let count = search?.results.count ?? 0
        let latency = search?.latencyMs
        if let latency {
            return "\(count) result\(count == 1 ? "" : "s") • \(latency) ms"
        }
        return "\(count) result\(count == 1 ? "" : "s")"
    }

    private var canStartChat: Bool {
        guard let search, !isLoading, !isRunning, !isStartingChat else {
            return false
        }
        return search.answerText?.isEmpty == false || !search.results.isEmpty
    }

    @ViewBuilder
    private var answerCard: some View {
        VStack(alignment: .leading, spacing: 10) {
            Text("Answer")
                .font(.sybil(.caption, weight: .semibold))
                .textCase(.uppercase)
                .foregroundStyle(SybilTheme.primary.opacity(0.92))

            if isRunning && (search?.answerText.orEmpty.isEmpty ?? true) {
                HStack(spacing: 8) {
                    ProgressView()
                        .controlSize(.small)
                        .tint(SybilTheme.textMuted)
                    Text("Generating answer…")
                        .font(.sybil(.footnote))
                        .foregroundStyle(SybilTheme.textMuted)
                }
            } else if let answer = search?.answerText, !answer.isEmpty {
                Markdown(answer)
                    .tint(SybilTheme.primary)
                    .foregroundStyle(SybilTheme.text)
                    .markdownTheme(.sybilReadable)
            }

            if let answerError = search?.answerError, !answerError.isEmpty {
                Text(answerError)
                    .font(.sybil(.footnote))
                    .foregroundStyle(SybilTheme.danger)
            }

            if let citations = search?.answerCitations, !citations.isEmpty {
                FlowLayout(spacing: 8) {
                    ForEach(Array(citations.prefix(8).enumerated()), id: \.offset) { index, citation in
                        if let link = citation.url ?? citation.id {
                            Link(destination: URL(string: link) ?? URL(string: "https://example.com")!) {
                                HStack(spacing: 6) {
                                    Text("[\(index + 1)]")
                                        .font(.sybil(.caption2, weight: .semibold))
                                        .foregroundStyle(SybilTheme.primary)
                                    Text(citation.title.orEmpty.isEmpty ? host(for: link) : citation.title.orEmpty)
                                        .font(.sybil(.caption))
                                        .lineLimit(1)
                                        .foregroundStyle(SybilTheme.text)
                                }
                .padding(.horizontal, 10)
                .padding(.vertical, 6)
                .background(
                    Capsule()
                        .fill(SybilTheme.primary.opacity(0.10))
                        .overlay(
                            Capsule()
                                .stroke(SybilTheme.primary.opacity(0.28), lineWidth: 1)
                        )
                )
                            }
                            .buttonStyle(.plain)
                        }
                    }
                }
            }
        }
        .padding(14)
        .background(
            RoundedRectangle(cornerRadius: 16)
                .fill(LinearGradient(colors: [SybilTheme.searchCard.opacity(0.98), SybilTheme.surface.opacity(0.78)], startPoint: .topLeading, endPoint: .bottomTrailing))
                .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(SybilTheme.border.opacity(0.88), lineWidth: 1)
                )
        )
        .frame(maxWidth: .infinity, alignment: .leading)
    }

    private func host(for raw: String) -> String {
        guard let url = URL(string: raw), let host = url.host else { return raw }
        if host.hasPrefix("www.") {
            return String(host.dropFirst(4))
        }
        return host
    }
}

private struct SearchResultCard: View {
    var result: SearchResultItem

    private var resolvedURL: URL? {
        URL(string: result.url)
    }

    var body: some View {
        HStack {
            VStack(alignment: .leading, spacing: 7) {
                Text(host)
                    .font(.sybil(.caption))
                    .foregroundStyle(SybilTheme.accent.opacity(0.9))
                    .lineLimit(1)
                
                if let resolvedURL {
                    Link(destination: resolvedURL) {
                        Text(result.title.orEmpty.orFallback(result.url))
                            .font(.sybil(.headline))
                            .foregroundStyle(SybilTheme.primary.opacity(0.96))
                            .lineSpacing(2)
                            .multilineTextAlignment(.leading)
                    }
                    .buttonStyle(.plain)
                } else {
                    Text(result.title.orEmpty.orFallback(result.url))
                        .font(.sybil(.headline))
                        .foregroundStyle(SybilTheme.primary.opacity(0.96))
                        .lineSpacing(2)
                }
                
                if let date = result.publishedDate, !date.isEmpty {
                    Text(date + (result.author.orEmpty.isEmpty ? "" : " • \(result.author.orEmpty)"))
                        .font(.sybil(.caption))
                        .foregroundStyle(SybilTheme.textMuted)
                } else if let author = result.author, !author.isEmpty {
                    Text(author)
                        .font(.sybil(.caption))
                        .foregroundStyle(SybilTheme.textMuted)
                }
                
                Text(result.url)
                    .font(.sybil(.footnote))
                    .foregroundStyle(SybilTheme.text.opacity(0.92))
                    .lineSpacing(2)
                    .lineLimit(3)
                    .textSelection(.enabled)
                
                if let highlights = result.highlights, !highlights.isEmpty {
                    ForEach(Array(highlights.prefix(2).enumerated()), id: \.offset) { _, highlight in
                        Text("• \(highlight)")
                            .font(.sybil(.caption))
                            .foregroundStyle(SybilTheme.textMuted)
                            .lineSpacing(2)
                            .fixedSize(horizontal: false, vertical: true)
                    }
                }
            }
            
            Spacer()
        }
        .padding(14)
        .background(
            RoundedRectangle(cornerRadius: 14)
                .fill(LinearGradient(colors: [SybilTheme.searchCard.opacity(0.96), SybilTheme.surface.opacity(0.72)], startPoint: .topLeading, endPoint: .bottomTrailing))
                .overlay(
                    RoundedRectangle(cornerRadius: 14)
                        .stroke(SybilTheme.border.opacity(0.84), lineWidth: 1)
                )
        )
        .frame(maxWidth: .infinity, alignment: .leading)
    }

    private var host: String {
        guard let resolvedURL, let host = resolvedURL.host else {
            return result.url
        }
        if host.hasPrefix("www.") {
            return String(host.dropFirst(4))
        }
        return host
    }
}

private struct FlowLayout<Content: View>: View {
    var spacing: CGFloat
    @ViewBuilder var content: Content

    init(spacing: CGFloat = 8, @ViewBuilder content: () -> Content) {
        self.spacing = spacing
        self.content = content()
    }

    var body: some View {
        VStack(alignment: .leading, spacing: spacing) {
            content
        }
    }
}

private extension Optional where Wrapped == String {
    var orEmpty: String {
        self ?? ""
    }
}

private extension String {
    func orFallback(_ fallback: String) -> String {
        isEmpty ? fallback : self
    }
}
