import SwiftUI
#if canImport(UIKit)
import UIKit
#endif

struct PrivateChatView: View {
    let chat: PrivateChatListItem
    let currentUserId: String?
    private let bottomAnchorId = "PrivateChatBottomAnchor"
    
    let lineLimitInChat = 6

    @StateObject private var viewModel: PrivateChatViewModel
    @State private var hasPositionedToBottom: Bool = false
    @State private var scrollToBottomTrigger: UUID = .init()
    @State private var isBottomAnchorVisible: Bool = true
    @State private var draftText: String = ""
    @State private var inputTab: ComposerTab = .chat
    @State private var isVideoPreferred: Bool = false
    @State private var legacyComposerHeight: CGFloat = 40
    @FocusState private var isComposerFocused: Bool
    @EnvironmentObject private var messageCenter: IncomingMessageCenter

    init(chat: PrivateChatListItem, currentUserId: String?) {
        self.chat = chat
        self.currentUserId = currentUserId
        _viewModel = StateObject(wrappedValue: PrivateChatViewModel(chatId: chat.chatId, currentUserId: currentUserId))
    }

    var body: some View {
        ScrollViewReader { proxy in
            ZStack(alignment: .bottomTrailing) {
                content
                    .onChange(of: viewModel.messages.count) { _ in
                        guard !viewModel.isLoadingMore else { return }
                        scrollToBottom(proxy: proxy)
                    }
                    .onChange(of: scrollToBottomTrigger) { _ in
                        scrollToBottom(proxy: proxy)
                    }

                if !isBottomAnchorVisible {
                    scrollToBottomButton(proxy: proxy)
                        .padding(.trailing, 12)
                        .padding(.bottom, 4)
                }
            }
        }
        .navigationTitle(title)
        .navigationBarTitleDisplayMode(.inline)
        .task {
            viewModel.loadInitialHistory()
        }
        .onAppear {
            messageCenter.activeChatId = chat.chatId
        }
        .onChange(of: viewModel.isInitialLoading) { isLoading in
            if isLoading {
                hasPositionedToBottom = false
            }
        }
        .safeAreaInset(edge: .bottom) {
            composer
        }
        .onDisappear {
            if messageCenter.activeChatId == chat.chatId {
                messageCenter.activeChatId = nil
            }
        }
    }

    @ViewBuilder
    private var content: some View {
        if viewModel.isInitialLoading && viewModel.messages.isEmpty {
            ProgressView(NSLocalizedString("Загрузка сообщений…", comment: ""))
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        } else if let error = viewModel.errorMessage, viewModel.messages.isEmpty {
            errorView(message: error)
        } else {
            ScrollView {
                LazyVStack(alignment: .leading, spacing: 12) {
                    if viewModel.isLoadingMore {
                        loadingMoreView
                    } else if viewModel.messages.isEmpty {
                        emptyState
                    }

                    ForEach(viewModel.messages) { message in
                        messageRow(for: message)
                            .id(message.id)
                            .onAppear {
                                guard hasPositionedToBottom else { return }
                                viewModel.loadMoreIfNeeded(for: message)
                            }
                    }

                    if let message = viewModel.errorMessage,
                       !message.isEmpty,
                       !viewModel.messages.isEmpty {
                        errorBanner(message: message)
                    }

                    Color.clear
                        .frame(height: 1)
                        .id(bottomAnchorId)
                        .onAppear { isBottomAnchorVisible = true }
                        .onDisappear { isBottomAnchorVisible = false }
                }
                .padding(.vertical, 12)
            }
            .simultaneousGesture(
                DragGesture().onChanged { value in
                    guard value.translation.height > 0 else { return }
                    isComposerFocused = false
                }
            )
            .refreshable {
                viewModel.refresh()
            }
        }
    }

    private var emptyState: some View {
        Text(NSLocalizedString("В чате пока нет сообщений.", comment: ""))
            .font(.footnote)
            .foregroundColor(.secondary)
            .frame(maxWidth: .infinity, alignment: .center)
            .padding(.top, 32)
    }

    private var loadingMoreView: some View {
        HStack {
            ProgressView()
            Text(NSLocalizedString("Загружаем ранние сообщения…", comment: ""))
                .font(.caption)
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, 8)
    }

    private func errorView(message: String) -> some View {
        VStack(spacing: 12) {
            Text(message)
                .font(.body)
                .multilineTextAlignment(.center)
                .foregroundColor(.primary)

            Button(action: { viewModel.refresh() }) {
                Text(NSLocalizedString("Повторить", comment: ""))
                    .font(.body)
            }
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }

    private func messageRow(for message: MessageItem) -> some View {
        let isCurrentUser = currentUserId.map { $0 == message.senderId } ?? false
        return HStack(alignment: .bottom, spacing: 12) {
            if isCurrentUser { Spacer(minLength: 32) }

            VStack(alignment: isCurrentUser ? .trailing : .leading, spacing: 6) {
//                if !isCurrentUser {
//                    Text(senderName(for: message))
//                        .font(.caption)
//                        .foregroundColor(.secondary)
//                }

                HStack(alignment: .bottom) {
                    Text(contentText(for: message))
                        .font(.body)
                        .foregroundColor(isCurrentUser ? .white : .primary)
                        .multilineTextAlignment(.leading)
                    
                    Text(timestamp(for: message))
                        .font(.caption2)
                        .foregroundColor(isCurrentUser ? Color.white.opacity(0.8) : .secondary)
                    
                }
            }
            .padding(.vertical, 10)
            .padding(.horizontal, 12)
            .background(isCurrentUser ? Color.accentColor : Color(.secondarySystemBackground))
            .clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
            .frame(maxWidth: messageBubbleMaxWidth, alignment: isCurrentUser ? .trailing : .leading)
            .fixedSize(horizontal: false, vertical: true)

            if !isCurrentUser { Spacer(minLength: 32) }
        }
        .padding(.horizontal, 16)
    }

    private var messageBubbleMaxWidth: CGFloat {
        min(UIScreen.main.bounds.width * 0.72, 360)
    }

    private func senderName(for message: MessageItem) -> String {
        if let full = message.senderData?.fullName, !full.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            return full
        }
        if let custom = message.senderData?.customName, !custom.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            return custom
        }
        if let login = message.senderData?.login, !login.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            return "@\(login)"
        }
        return message.senderId
    }

    private func timestamp(for message: MessageItem) -> String {
        guard let date = message.createdAt else {
            return ""
        }
        return Self.timeFormatter.string(from: date)
    }

    private func contentText(for message: MessageItem) -> String {
        guard let content = message.content?.trimmingCharacters(in: .whitespacesAndNewlines), !content.isEmpty else {
            return NSLocalizedString("(без текста)", comment: "")
        }
        return content
    }

    private func errorBanner(message: String) -> some View {
        HStack {
            Image(systemName: "exclamationmark.triangle.fill")
                .foregroundColor(.orange)
            Text(message)
                .font(.footnote)
                .foregroundColor(.primary)
        }
        .padding()
        .background(Color(.secondarySystemBackground))
        .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
        .padding(.horizontal, 16)
        .padding(.top, 8)
    }

    private var composer: some View {
        VStack(spacing: 10) {
            HStack(alignment: .bottom, spacing: 4) {
                Button(action: {  }) { // переключатель на стикеры
                    Image(systemName: "paperclip")
                        .font(.system(size: 18, weight: .semibold))
                        .foregroundColor(.secondary)
                }
//                .buttonStyle(ComposerIconButtonStyle())
                .frame(width: 36, height: 36)

                ZStack(alignment: .bottomTrailing) {
                    Group {
                        if #available(iOS 16.0, *) {
                            TextField(inputTab.placeholder, text: $draftText, axis: .vertical)
                                .lineLimit(1...lineLimitInChat)
                                .focused($isComposerFocused)
                                .submitLabel(.send)
                                .disabled(currentUserId == nil)
                                .onSubmit { sendCurrentMessage() }
                        } else {
                            LegacyMultilineTextView(
                                text: $draftText,
                                placeholder: inputTab.placeholder,
                                isFocused: Binding(
                                    get: { isComposerFocused },
                                    set: { isComposerFocused = $0 }
                                ),
                                isEnabled: currentUserId != nil,
                                minHeight: 10,
                                maxLines: lineLimitInChat,
                                calculatedHeight: $legacyComposerHeight,
                                onSubmit: sendCurrentMessage
                            )
                            .frame(height: legacyComposerHeight)
                        }
                    }
                    .padding(.top, 10)
                    .padding(.leading, 12)
                    .padding(.trailing, 44)
                    .padding(.bottom, 10)
                    .frame(maxWidth: .infinity, minHeight: 40, alignment: .bottomLeading)

                    Button(action: {  }) { // переключатель на стикеры
                        Image(systemName: "face.smiling")
                            .font(.system(size: 18, weight: .semibold))
                            .foregroundColor(.secondary)
                    }
                    .padding(.trailing, 12)
                    .padding(.bottom, 10)
                }
                .frame(minHeight: 40, alignment: .bottom)
                .background(Color(.secondarySystemBackground))
                .clipShape(RoundedRectangle(cornerRadius: 18, style: .continuous))
                .alignmentGuide(.bottom) { dimension in
                    dimension[VerticalAlignment.bottom] - 2
                }

                if !isSendAvailable {
                    Button(action: { isVideoPreferred.toggle() }) {
                        Image(systemName: isVideoPreferred ? "video.fill" : "mic.fill")
                            .font(.system(size: 18, weight: .semibold))
                            .foregroundColor(.secondary)
                    }
//                    .buttonStyle(ComposerIconButtonStyle())
                    .frame(width: 36, height: 36)
                } else {
                    sendButton
                }
            }
        }
        .padding(.horizontal, 6)
        .padding(.top, 10)
        .padding(.bottom, 8)
        .background(.ultraThinMaterial)
    }

    private func scrollToBottomButton(proxy: ScrollViewProxy) -> some View {
        Button {
            scrollToBottom(proxy: proxy)
        } label: {
            Image(systemName: "arrow.down")
                .font(.system(size: 18, weight: .semibold))
                .foregroundColor(.white)
                .frame(width: 44, height: 44)
//                .background(Color.accentColor)
                .background(Color(.secondarySystemBackground))
                .clipShape(Circle())
//                .overlay(
//                    Circle().stroke(Color.white.opacity(0.35), lineWidth: 1)
//                )
        }
        .buttonStyle(.plain)
        .shadow(color: Color.black.opacity(0.2), radius: 4, x: 0, y: 2)
    }

    private var isSendDisabled: Bool {
        draftText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || currentUserId == nil
    }

    private var isSendAvailable: Bool {
        !draftText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && currentUserId != nil
    }

    private var sendButton: some View {
        Button(action: sendCurrentMessage) {
            Image(systemName: "leaf.fill")
                .font(.system(size: 16, weight: .semibold))
                .foregroundColor(Color.white.opacity(isSendDisabled ? 0.6 : 1))
                .frame(width: 36, height: 36)
                .background(isSendDisabled ? Color.accentColor.opacity(0.4) : Color.accentColor)
                .clipShape(Circle())
        }
        .disabled(isSendDisabled)
        .buttonStyle(.plain)
    }

//    private func composerToolbarButton(systemName: String, action: @escaping () -> Void) -> some View {
//        Button(action: action) {
//            Image(systemName: systemName)
//                .font(.system(size: 16, weight: .medium))
//    }

    private func composerModeButton(_ tab: ComposerTab) -> some View {
        Button(action: { inputTab = tab }) {
            Text(tab.title)
                .font(.caption)
                .fontWeight(inputTab == tab ? .semibold : .regular)
                .padding(.vertical, 8)
                .padding(.horizontal, 14)
                .background(
                    Group {
                        if inputTab == tab {
                            Color.accentColor.opacity(0.15)
                        } else {
                            Color(.secondarySystemBackground)
                        }
                    }
                )
                .foregroundColor(inputTab == tab ? .accentColor : .primary)
                .clipShape(Capsule())
        }
        .buttonStyle(.plain)
    }

    private func sendCurrentMessage() {
        let text = draftText.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !text.isEmpty else { return }

        draftText = ""
        scrollToBottomTrigger = .init()
        viewModel.sendMessage(text: text) { success in
            if success {
                hasPositionedToBottom = true
            }
        }
    }

    private func scrollToBottom(proxy: ScrollViewProxy) {
        hasPositionedToBottom = true

        let targetId = viewModel.messages.last?.id ?? bottomAnchorId

        DispatchQueue.main.async {
            withAnimation(.easeInOut(duration: 0.2)) {
                proxy.scrollTo(targetId, anchor: .bottom)
            }
        }
    }

    private struct ComposerIconButtonStyle: ButtonStyle {
        func makeBody(configuration: Configuration) -> some View {
            configuration.label
                .frame(width: 36, height: 36)
                .background(Color(.secondarySystemBackground))
                .clipShape(Circle())
                .overlay(
                    Circle().stroke(Color.secondary.opacity(0.15))
                )
                .scaleEffect(configuration.isPressed ? 0.94 : 1)
                .opacity(configuration.isPressed ? 0.75 : 1)
        }
    }

    private enum ComposerTab: String {
        case chat
        case stickers

        var title: String {
            switch self {
            case .chat: return NSLocalizedString("Чат", comment: "")
            case .stickers: return NSLocalizedString("Стикеры", comment: "")
            }
        }

        var iconName: String {
            switch self {
            case .chat: return "text.bubble"
            case .stickers: return "face.smiling"
            }
        }

        var placeholder: String {
            switch self {
            case .chat: return NSLocalizedString("Сообщение", comment: "")
            case .stickers: return NSLocalizedString("Поиск стикеров", comment: "")
            }
        }
    }

    private static let timeFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateStyle = .none
        formatter.timeStyle = .short
        return formatter
    }()

    private var title: String {
        if let full = chat.chatData?.fullName, !full.isEmpty {
            return full
        }
        if let custom = chat.chatData?.customName, !custom.isEmpty {
            return custom
        }
        if let login = chat.chatData?.login, !login.isEmpty {
            return "@\(login)"
        }
        return NSLocalizedString("Чат", comment: "")
    }
}

#if canImport(UIKit)
private struct LegacyMultilineTextView: UIViewRepresentable {
    @Binding var text: String
    var placeholder: String
    @Binding var isFocused: Bool
    var isEnabled: Bool
    var minHeight: CGFloat
    var maxLines: Int
    @Binding var calculatedHeight: CGFloat
    var onSubmit: (() -> Void)?

    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.delegate = context.coordinator
        textView.backgroundColor = .clear
        textView.textContainerInset = .zero
        textView.textContainer.lineFragmentPadding = 0
        textView.isScrollEnabled = false
        textView.font = UIFont.preferredFont(forTextStyle: .body)
        textView.text = text
        textView.returnKeyType = .send
        textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

        let placeholderLabel = context.coordinator.placeholderLabel
        placeholderLabel.text = placeholder
        placeholderLabel.font = textView.font
        placeholderLabel.textColor = UIColor.secondaryLabel
        placeholderLabel.numberOfLines = 1
        placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
        textView.addSubview(placeholderLabel)

        NSLayoutConstraint.activate([
            placeholderLabel.topAnchor.constraint(equalTo: textView.topAnchor),
            placeholderLabel.leadingAnchor.constraint(equalTo: textView.leadingAnchor),
            placeholderLabel.trailingAnchor.constraint(lessThanOrEqualTo: textView.trailingAnchor)
        ])

        context.coordinator.updatePlaceholderVisibility(for: textView)
        DispatchQueue.main.async {
            Self.recalculateHeight(
                for: textView,
                result: calculatedHeightBinding,
                minHeight: minHeight,
                maxLines: maxLines
            )
        }

        return textView
    }

    func updateUIView(_ uiView: UITextView, context: Context) {
        context.coordinator.parent = self

        if uiView.text != text {
            uiView.text = text
        }

        uiView.isEditable = isEnabled
        uiView.isSelectable = isEnabled
        uiView.textColor = isEnabled ? UIColor.label : UIColor.secondaryLabel

        let placeholderLabel = context.coordinator.placeholderLabel
        if placeholderLabel.text != placeholder {
            placeholderLabel.text = placeholder
        }
        placeholderLabel.font = uiView.font
        context.coordinator.updatePlaceholderVisibility(for: uiView)

        if isFocused && !uiView.isFirstResponder {
            uiView.becomeFirstResponder()
        } else if !isFocused && uiView.isFirstResponder {
            uiView.resignFirstResponder()
        }

        Self.recalculateHeight(
            for: uiView,
            result: calculatedHeightBinding,
            minHeight: minHeight,
            maxLines: maxLines
        )
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    private var calculatedHeightBinding: Binding<CGFloat> {
        Binding(get: { calculatedHeight }, set: { calculatedHeight = $0 })
    }

    private static func recalculateHeight(for textView: UITextView, result: Binding<CGFloat>, minHeight: CGFloat, maxLines: Int) {
        let width = textView.bounds.width
        guard width > 0 else {
            DispatchQueue.main.async {
                recalculateHeight(for: textView, result: result, minHeight: minHeight, maxLines: maxLines)
            }
            return
        }

        let fittingSize = CGSize(width: width, height: .greatestFiniteMagnitude)
        let targetSize = textView.sizeThatFits(fittingSize)
        let lineHeight = textView.font?.lineHeight ?? UIFont.preferredFont(forTextStyle: .body).lineHeight
        let maxHeight = minHeight + lineHeight * CGFloat(max(maxLines - 1, 0))
        let clampedHeight = min(max(targetSize.height, minHeight), maxHeight)
        let shouldScroll = targetSize.height > maxHeight + 0.5

        if abs(result.wrappedValue - clampedHeight) > 0.5 {
            let newHeight = clampedHeight
            DispatchQueue.main.async {
                if abs(result.wrappedValue - newHeight) > 0.5 {
                    result.wrappedValue = newHeight
                }
            }
        }

        textView.isScrollEnabled = shouldScroll
    }

    final class Coordinator: NSObject, UITextViewDelegate {
        var parent: LegacyMultilineTextView
        let placeholderLabel = UILabel()

        init(parent: LegacyMultilineTextView) {
            self.parent = parent
        }

        func textViewDidBeginEditing(_ textView: UITextView) {
            if !parent.isFocused {
                parent.isFocused = true
            }
        }

        func textViewDidEndEditing(_ textView: UITextView) {
            if parent.isFocused {
                parent.isFocused = false
            }
        }

        func textViewDidChange(_ textView: UITextView) {
            if parent.text != textView.text {
                parent.text = textView.text
            }
            updatePlaceholderVisibility(for: textView)
            LegacyMultilineTextView.recalculateHeight(for: textView, result: parent.calculatedHeightBinding, minHeight: parent.minHeight, maxLines: parent.maxLines)
        }

        func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
            if text == "\n" {
                if let onSubmit = parent.onSubmit {
                    DispatchQueue.main.async {
                        onSubmit()
                    }
                    return false
                }
            }
            return true
        }

        func updatePlaceholderVisibility(for textView: UITextView) {
            placeholderLabel.isHidden = !textView.text.isEmpty
        }
    }
}
#endif

// MARK: - Preview

// Previews intentionally omitted - MessageItem has custom decoding-only initializer.
