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

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

    @AppStorage("chatBubbleDecorationsEnabled") private var areBubbleDecorationsEnabled: Bool = true
    @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
    @State private var isProfilePresented: Bool = false
    @FocusState private var isComposerFocused: Bool
    @EnvironmentObject private var themeManager: ThemeManager
    @EnvironmentObject private var messageCenter: IncomingMessageCenter
    @Environment(\.dismiss) private var dismiss

    @State private var previousStandardAppearance: UINavigationBarAppearance?
    @State private var previousScrollEdgeAppearance: UINavigationBarAppearance?
    @State private var previousCompactAppearance: UINavigationBarAppearance?

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

    var body: some View {
        ZStack {
            ScrollViewReader { proxy in
                ZStack(alignment: .bottomTrailing) {
                    content
                        .onChange(of: viewModel.messages.count) { _ in
                            if isBottomAnchorVisible {
                                scrollToBottom(proxy: proxy)
                            }
                        }
                        .onChange(of: scrollToBottomTrigger) { _ in
                            scrollToBottom(proxy: proxy)
                        }

                    if !isBottomAnchorVisible && !viewModel.isInitialLoading {
                        scrollToBottomButton(proxy: proxy)
                            .padding(.trailing, 12)
                            .padding(.bottom, 4)
                    }
                }
            }

            NavigationLink(
                destination: MessageProfileView(chat: chat, currentUserId: currentUserId),
                isActive: $isProfilePresented
            ) {
                EmptyView()
            }
            .hidden()
        }
        .alert("Ошибка отправки", isPresented: Binding(
            get: { viewModel.sendingErrorMessage != nil },
            set: { if !$0 { viewModel.sendingErrorMessage = nil } }
        ), actions: {
            Button("OK") { }
        }, message: {
            Text(viewModel.sendingErrorMessage ?? "Не удалось отправить сообщение.")
        })
        .navigationTitle(toolbarTitle)
        .navigationBarTitleDisplayMode(.inline)
//        .navigationBarBackButtonHidden(true)
//        .toolbar {
//            ToolbarItem(placement: .principal) {
//                chatToolbarContent
//            }
//        }
        .toolbar {
//            ToolbarItem(placement: .navigationBarLeading) {
//                Button(action: { dismiss() }) {
//                    Image(systemName: "chevron.left")
//                        .font(.system(size: 17, weight: .semibold))
//                        .foregroundColor(.accentColor)
//                }
//            }
            
            ToolbarItem(placement: .principal) {
                Button(action: openProfile) {
                    nameStatusView
                }
                .buttonStyle(.plain)
            }
            

            ToolbarItem(placement: .navigationBarTrailing) {
                avatarButton
            }
        }
        .task {
            viewModel.loadInitialHistory()
        }
        .onAppear {
            messageCenter.activeChatId = chat.chatId

            previousStandardAppearance = UINavigationBar.appearance().standardAppearance
            previousScrollEdgeAppearance = UINavigationBar.appearance().scrollEdgeAppearance
            previousCompactAppearance = UINavigationBar.appearance().compactAppearance

            let appearance = UINavigationBarAppearance()
            appearance.configureWithDefaultBackground()
//            appearance.shadowColor = .clear

            UINavigationBar.appearance().standardAppearance = appearance
            UINavigationBar.appearance().scrollEdgeAppearance = appearance
            UINavigationBar.appearance().compactAppearance = appearance
        }
        .onChange(of: viewModel.isInitialLoading) { isLoading in
            if isLoading {
                hasPositionedToBottom = false
            } else if !viewModel.messages.isEmpty {
                scrollToBottomTrigger = .init()
            }
        }
        .safeAreaInset(edge: .bottom) {
            composer
        }
        .onDisappear {
            if messageCenter.activeChatId == chat.chatId {
                messageCenter.activeChatId = nil
            }

            if let standard = previousStandardAppearance {
                UINavigationBar.appearance().standardAppearance = standard
            }
            UINavigationBar.appearance().scrollEdgeAppearance = previousScrollEdgeAppearance
            UINavigationBar.appearance().compactAppearance = previousCompactAppearance
        }
    }

    @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 {
            messagesList
        }
    }

    private var messagesList: some View {
        ScrollView {
            LazyVStack(alignment: .leading, spacing: 0) {
                Color.clear
                    .frame(height: 1)
                    .id(bottomAnchorId)
                    .onAppear { isBottomAnchorVisible = true }
                    .onDisappear { isBottomAnchorVisible = false }

                if let message = viewModel.errorMessage,
                   !message.isEmpty,
                   !viewModel.messages.isEmpty {
                    errorBanner(message: message)
                        .scaleEffect(x: 1, y: -1, anchor: .center)
                }

                ForEach(decoratedMessages.reversed()) { decoratedMessage in
                    messageRow(for: decoratedMessage)
                        .id(decoratedMessage.id)
                        .scaleEffect(x: 1, y: -1, anchor: .center)
                        .onAppear {
                            guard hasPositionedToBottom else { return }
                            viewModel.loadMoreIfNeeded(for: decoratedMessage.message)
                        }
                }

                if viewModel.isLoadingMore {
                    loadingMoreView
                        .scaleEffect(x: 1, y: -1, anchor: .center)
                } else if !viewModel.hasMore && !viewModel.messages.isEmpty {
                    noMoreMessagesView
                        .scaleEffect(x: 1, y: -1, anchor: .center)
                } else if viewModel.messages.isEmpty {
                    emptyState
                        .scaleEffect(x: 1, y: -1, anchor: .center)
                }
            }
            .padding(.vertical, 8)
        }
        .scaleEffect(x: 1, y: -1, anchor: .center)
        .simultaneousGesture(
            DragGesture().onChanged { value in
                guard value.translation.height > 0 else { return }
                isComposerFocused = false
            }
        )
    }

    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 var noMoreMessagesView: some View {
        Text(NSLocalizedString("Больше сообщений нет", comment: "Chat history top reached"))
            .font(.caption)
            .foregroundColor(.secondary)
            .padding(.vertical, 16)
            .frame(maxWidth: .infinity)
    }

    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 decoratedMessage: DecoratedMessage) -> some View {
        let message = decoratedMessage.message
        let isCurrentUser = currentUserId.map { $0 == message.senderId } ?? false
        let hasDecorations = decoratedMessage.showHorns || decoratedMessage.showLegs
        
        let topPadding: CGFloat = decoratedMessage.showHorns ? 5 : -12
        let verticalPadding: CGFloat = hasDecorations ? 0 : 0
        
        if #available(iOS 16.0, *) {
            return HStack(alignment: .bottom, spacing: 8) {
                if isCurrentUser { Spacer(minLength: 32) }
                
                messageBubble(
                    for: message,
                    decorations: decoratedMessage,
                    isCurrentUser: isCurrentUser
                )
                
                if !isCurrentUser { Spacer(minLength: 32) }
            }
            .padding(.horizontal, 8)
            .padding(.top, topPadding)
            .padding(.vertical, verticalPadding)
            .contextMenu(menuItems: {
                if isCurrentUser {
                    if message.isViewed == true {
                        Text("Прочитано") // Placeholder for read status
                    }
                    Button(action: {
                        // Reply action
                    }) {
                        Text("Ответить")
                        Image(systemName: "arrowshape.turn.up.left")
                    }
                    Button(action: {
                        // Copy action
                    }) {
                        Text("Копировать")
                        Image(systemName: "doc.on.doc")
                    }
                    Button(action: {
                        // Edit action
                    }) {
                        Text("Изменить")
                        Image(systemName: "pencil")
                    }
                    Button(action: {
                        // Pin action
                    }) {
                        Text("Закрепить")
                        Image(systemName: "pin")
                    }
                    Button(action: {
                        // Forward action
                    }) {
                        Text("Переслать")
                        Image(systemName: "arrowshape.turn.up.right")
                    }
                    Button(role: .destructive, action: {
                        // Delete action
                    }) {
                        Text("Удалить")
                        Image(systemName: "trash")
                    }
                    Button(action: {
                        // Select action
                    }) {
                        Text("Выбрать")
                        Image(systemName: "checkmark.circle")
                    }
                } else {
                    Button(action: {
                        // Reply action
                    }) {
                        Text("Ответить")
                        Image(systemName: "arrowshape.turn.up.left")
                    }
                    Button(action: {
                        // Copy action
                    }) {
                        Text("Копировать")
                        Image(systemName: "doc.on.doc")
                    }
                    Button(action: {
                        // Pin action
                    }) {
                        Text("Закрепить")
                        Image(systemName: "pin")
                    }
                    Button(action: {
                        // Forward action
                    }) {
                        Text("Переслать")
                        Image(systemName: "arrowshape.turn.up.right")
                    }
                    Button(role: .destructive, action: {
                        // Delete action
                    }) {
                        Text("Удалить")
                        Image(systemName: "trash")
                    }
                    Button(action: {
                        // Select action
                    }) {
                        Text("Выбрать")
                        Image(systemName: "checkmark.circle")
                    }
                }
            }, preview: {
                messageBubble(
                    for: message,
                    decorations: decoratedMessage,
                    isCurrentUser: isCurrentUser
                )
            })
        } else {
            return HStack(alignment: .bottom, spacing: 8) {
                if isCurrentUser { Spacer(minLength: 32) }
                
                messageBubble(
                    for: message,
                    decorations: decoratedMessage,
                    isCurrentUser: isCurrentUser
                )
                
                if !isCurrentUser { Spacer(minLength: 32) }
            }
            .padding(.horizontal, 8)
            .padding(.top, topPadding)
            .padding(.vertical, verticalPadding)
            .contextMenu {
                if isCurrentUser {
                    if message.isViewed == true {
                        Text("Прочитано") // Placeholder for read status
                    }
                    Button(action: {
                        // Reply action
                    }) {
                        Text("Ответить")
                        Image(systemName: "arrowshape.turn.up.left")
                    }
                    Button(action: {
                        // Copy action
                    }) {
                        Text("Копировать")
                        Image(systemName: "doc.on.doc")
                    }
                    Button(action: {
                        // Edit action
                    }) {
                        Text("Изменить")
                        Image(systemName: "pencil")
                    }
                    Button(action: {
                        // Pin action
                    }) {
                        Text("Закрепить")
                        Image(systemName: "pin")
                    }
                    Button(action: {
                        // Forward action
                    }) {
                        Text("Переслать")
                        Image(systemName: "arrowshape.turn.up.right")
                    }
                    Button(role: .destructive, action: {
                        // Delete action
                    }) {
                        Text("Удалить")
                        Image(systemName: "trash")
                    }
                    Button(action: {
                        // Select action
                    }) {
                        Text("Выбрать")
                        Image(systemName: "checkmark.circle")
                    }
                } else {
                    Button(action: {
                        // Reply action
                    }) {
                        Text("Ответить")
                        Image(systemName: "arrowshape.turn.up.left")
                    }
                    Button(action: {
                        // Copy action
                    }) {
                        Text("Копировать")
                        Image(systemName: "doc.on.doc")
                    }
                    Button(action: {
                        // Pin action
                    }) {
                        Text("Закрепить")
                        Image(systemName: "pin")
                    }
                    Button(action: {
                        // Forward action
                    }) {
                        Text("Переслать")
                        Image(systemName: "arrowshape.turn.up.right")
                    }
                    Button(role: .destructive, action: {
                        // Delete action
                    }) {
                        Text("Удалить")
                        Image(systemName: "trash")
                    }
                    Button(action: {
                        // Select action
                    }) {
                        Text("Выбрать")
                        Image(systemName: "checkmark.circle")
                    }
                }
            }
        }
    }

    private func messageBubble(
        for message: MessageItem,
        decorations: DecoratedMessage,
        isCurrentUser: Bool
    ) -> some View {
        let timeText = timestamp(for: message)
        let bubbleColor = isCurrentUser ? Color.accentColor : Color(.secondarySystemBackground)
        let foregroundColor = isCurrentUser ? Color.white : Color.primary

        // Use a single HStack with bottom alignment to keep text and time on the same line,
        // with the time aligning to the bottom.
        return HStack(alignment: .bottom, spacing: 8) {
            Text(contentText(for: message))
                .font(.body)
                .foregroundColor(foregroundColor)
                .multilineTextAlignment(.leading)

            // This view contains the time and the optional checkmark.
            // It's pushed to the right by the expanding Text view.
            HStack(spacing: 4) {
                Text(timeText)
                    .font(.caption2)
                    .foregroundColor(isCurrentUser ? foregroundColor.opacity(0.85) : .secondary)

                if isCurrentUser {
                    Image(systemName: (message.isViewed ?? false) ? "checkmark.circle.fill" : "checkmark.circle")
                        .font(.system(size: 12, weight: .semibold))
                        .foregroundColor(isCurrentUser ? foregroundColor.opacity(0.85) : .secondary)
                }
            }
            .offset(y: 3) // Move the timestamp view down
        }
        .padding(.vertical, 15)
        .padding(.horizontal, 15)
        .background(
            MessageBubbleShape(
                decorationsEnabled: areBubbleDecorationsEnabled,
                showHornsRaw: decorations.showHorns,
                showLegsRaw: decorations.showLegs
            )
            .fill(bubbleColor)
        )
        .frame(maxWidth: messageBubbleMaxWidth, alignment: isCurrentUser ? .trailing : .leading)
        .fixedSize(horizontal: false, vertical: true)
    }

    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 var decoratedMessages: [DecoratedMessage] {
        let messages = viewModel.messages
        guard !messages.isEmpty else { return [] }

        var result: [DecoratedMessage] = []
        result.reserveCapacity(messages.count)

        for (index, message) in messages.enumerated() {
            let previousSender = index > 0 ? messages[index - 1].senderId : nil
            let nextSender = index < messages.count - 1 ? messages[index + 1].senderId : nil

            let showHorns = previousSender != message.senderId
            let showLegs = nextSender != message.senderId

            result.append(
                DecoratedMessage(
                    message: message,
                    showHorns: showHorns,
                    showLegs: showLegs
                )
            )
        }
        return result
    }

    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)
                    
                    HStack{
                        if draftText.count > 2047 {
                            Text("\(draftText.count) / \(viewModel.maxMessageLength)")
                                .font(.caption2)
                                .fontWeight(.medium)
                                .foregroundColor(draftText.count > viewModel.maxMessageLength ? .red : .secondary)
                        }
                        
                        Button(action: {  }) { // переключатель на стикеры
                            Image(systemName: "face.smiling")
                                .font(.system(size: 18, weight: .semibold))
                                .foregroundColor(.secondary)
                        }
                        .padding(.trailing, 12)
                        .padding(.bottom, 10)
                    }

//                    if draftText.count > 300 {
//                        Text("\(draftText.count) / \(viewModel.maxMessageLength)")
//                            .font(.caption2)
//                            .fontWeight(.medium)
//                            .foregroundColor(draftText.count > viewModel.maxMessageLength ? .red : .secondary)
//                            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing)
//                            .padding(.trailing, 12)
//                            .padding(.top, 4)
//                    }
                }
                .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)
        .modifier(ComposerBackgroundModifier(theme: themeManager.theme))
    }

    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 }

        scrollToBottomTrigger = .init()
        viewModel.sendMessage(text: text) { success in
            if success {
                draftText = ""
                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: .top)
            }
        }
    }

    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 {
        switch chat.chatType {
        case .self:
            return NSLocalizedString("Избранные сообщения", comment: "Saved messages title")
        case .privateChat, .unknown:
            if let custom = trimmed(chat.chatData?.customName) {
                return custom
            }
            if let full = trimmed(chat.chatData?.fullName) {
                return full
            }
            if let login = trimmed(chat.chatData?.login) {
                return "@\(login)"
            }
            return NSLocalizedString("Неизвестный пользователь", comment: "Unknown chat title")
        }
    }

    private var toolbarTitle: String {
        officialDisplayName ?? title
    }

    private var offlineStatusText: String {
        NSLocalizedString("Оффлайн", comment: "Offline status placeholder")
    }

    private var loginDisplay: String? {
        guard let login = trimmed(chat.chatData?.login) else {
            return nil
        }
        return "@\(login)"
    }

    private var isOfficial: Bool {
        chat.chatData?.isOfficial ?? false
    }

    private var officialDisplayName: String? {
        guard isOfficial else { return nil }

        if let customName = trimmed(chat.chatData?.customName) {
            return customName
        }

        if let name = trimmed(chat.chatData?.fullName) {
            return NSLocalizedString(name, comment: "Official chat name")
        }

        return loginDisplay
    }

    private var isDeletedUser: Bool {
        guard chat.chatType != .self else { return false }
        return trimmed(chat.chatData?.login) == nil
    }

    private var avatarBackgroundColor: Color {
        if isDeletedUser {
            return Color(.systemGray5)
        }
        return isOfficial ? Color.accentColor.opacity(0.85) : Color.accentColor.opacity(0.15)
    }

    private var avatarTextColor: Color {
        if isDeletedUser {
            return Color.accentColor
        }
        return isOfficial ? Color.white : Color.accentColor
    }

    private var deletedUserSymbolName: String {
        "person.slash"
    }

    private var avatarUrl: URL? {
        guard let chatData = chat.chatData,
              let fileId = chatData.avatars?.current?.fileId else {
            return nil
        }
        let userId = chatData.userId
        return URL(string: "\(AppConfig.API_SERVER)/v1/storage/download/avatar/\(userId)?file_id=\(fileId)")
    }

    private var avatarInitial: String {
        if let name = trimmed(chat.chatData?.customName) ?? trimmed(chat.chatData?.fullName) {
            let components = name.split(separator: " ")
            let initials = components.prefix(2).compactMap { $0.first }
            if !initials.isEmpty {
                return initials.map { String($0) }.joined().uppercased()
            }
        }

        if let login = trimmed(chat.chatData?.login) {
            return String(login.prefix(1)).uppercased()
        }

        return "?"
    }

    private func trimmed(_ string: String?) -> String? {
        guard let string = string?.trimmingCharacters(in: .whitespacesAndNewlines), !string.isEmpty else {
            return nil
        }
        return string
    }

    private var chatToolbarContent: some View {
        HStack(spacing: 12) {
            backButton

//            Spacer(minLength: 0)

            nameStatusButton
                .frame(maxWidth: .infinity)

//            Spacer(minLength: 0)

            avatarButton
        }
        .frame(maxWidth: .infinity, minHeight: headerAvatarSize, alignment: .center)
    }

    @ViewBuilder
    private var nameStatusView: some View {
        VStack(spacing: 2) {
            if let officialName = officialDisplayName {
                HStack(spacing: 4) {
                    nameText(officialName, weight: .semibold)

                    Image(systemName: "checkmark.seal.fill")
                        .foregroundColor(Color.accentColor)
                        .font(.caption)
                }
            } else {
                nameText(title, weight: .semibold)
            }

            Text(offlineStatusText)
                .font(.caption)
                .foregroundColor(.secondary)
        }
        .multilineTextAlignment(.center)
    }

    @ViewBuilder
    private var avatarView: some View {
        if let url = avatarUrl,
           let fileId = chat.chatData?.avatars?.current?.fileId,
           let userId = currentUserId {
            CachedAvatarView(url: url, fileId: fileId, userId: userId) {
                headerPlaceholderAvatar
            }
            .aspectRatio(contentMode: .fill)
            .frame(width: headerAvatarSize, height: headerAvatarSize)
            .clipShape(Circle())
        } else {
            headerPlaceholderAvatar
        }
    }

    private var nameStatusButton: some View {
        Button(action: openProfile) {
            nameStatusView
        }
        .buttonStyle(.plain)
    }

    private var avatarButton: some View {
        Button(action: openProfile) {
            avatarView
        }
        .buttonStyle(.plain)
    }

    private func nameText(_ text: String, weight: Font.Weight) -> some View {
        Group {
            if #available(iOS 16.0, *) {
                Text(text)
                    .font(.headline)
                    .fontWeight(weight)
                    .foregroundColor(.primary)
                    .lineLimit(1)
                    .truncationMode(.tail)
                    .strikethrough(isDeletedUser, color: Color.secondary)
            } else {
                Text(text)
                    .font(.headline)
                    .fontWeight(weight)
                    .foregroundColor(.primary)
                    .lineLimit(1)
                    .truncationMode(.tail)
            }
        }
    }

    private var backButton: some View {
        Button(action: { dismiss() }) {
            Image(systemName: "chevron.left")
                .font(.system(size: 17, weight: .semibold))
                .foregroundColor(.accentColor)
        }
        .frame(width: headerAvatarSize, height: headerAvatarSize)
        .contentShape(Rectangle())
    }

    private func openProfile() {
        isProfilePresented = true
    }

private var headerPlaceholderAvatar: some View {
    Circle()
        .fill(avatarBackgroundColor)
        .frame(width: headerAvatarSize, height: headerAvatarSize)
        .overlay(
            Group {
                if isDeletedUser {
                    Image(systemName: deletedUserSymbolName)
                        .symbolRenderingMode(.hierarchical)
                        .font(.system(size: headerAvatarSize * 0.45, weight: .semibold))
                        .foregroundColor(avatarTextColor)
                } else {
                    Text(avatarInitial)
                        .font(.system(size: headerAvatarSize * 0.5, weight: .semibold))
                        .foregroundColor(avatarTextColor)
                }
            }
        )
}
}


private struct ComposerBackgroundModifier: ViewModifier {
    let theme: Theme

    @ViewBuilder
    func body(content: Content) -> some View {
        if theme == .oledDark {
            content
                .background(Color.black.opacity(0.85)) // ← глубокий чёрный
//                .overlay(
//                    Color.black.opacity(0.25)           // ← лёгкое затемнение сверху
//                        .allowsHitTesting(false)
//                )
//            content.background(.ultraThinMaterial)
//            content.background(Color.black)
//            content.background(Color(white: 0.15))
        } else {
            content.background(.ultraThinMaterial)
        }
    }
}


/// Helper model that stores a message alongside horn/leg flags for grouping sequences.
private struct DecoratedMessage: Identifiable {
    let message: MessageItem
    let showHorns: Bool
    let showLegs: Bool

    var id: MessageItem.ID { message.id }
}

/// Decorative bubble with two horns on top and two legs on bottom to mimic cartoon-style speech clouds.
private struct MessageBubbleShape: Shape {
    var cornerRadius: CGFloat = 18
    var hornHeight: CGFloat = 10
    var hornWidth: CGFloat = 16
    var hornSpacing: CGFloat = 12
    var legHeight: CGFloat = 6
    var legWidth: CGFloat = 18
    var legSpacing: CGFloat = 14
    
    var decorationsEnabled: Bool = true
    var showHornsRaw: Bool = true
    var showLegsRaw: Bool = true
    
    var showHorns: Bool { decorationsEnabled && showHornsRaw }
    var showLegs: Bool { decorationsEnabled && showLegsRaw }

    func path(in rect: CGRect) -> Path {
        var path = Path()
        guard rect.width > 0, rect.height > 0 else { return path }

        let radius = min(cornerRadius, min(rect.width, rect.height) / 2)
        let innerTop = rect.minY + hornHeight
        let innerBottom = rect.maxY - legHeight
        let left = rect.minX
        let right = rect.maxX

        let horizontalSpan = max(0, rect.width - 2 * radius)

        let hornsEnabled = showHorns && horizontalSpan > 0.5
        let legsEnabled = showLegs && horizontalSpan > 0.5

        let effectiveHornWidth = hornsEnabled ? min(hornWidth, horizontalSpan / 2) : 0
        let effectiveLegWidth = legsEnabled ? min(legWidth, horizontalSpan / 2) : 0

        let hornSpacingCandidate = max(horizontalSpan - effectiveHornWidth * 2, 0) / 2
        let legSpacingCandidate = max(horizontalSpan - effectiveLegWidth * 2, 0) / 2

        let effectiveHornSpacing = hornsEnabled ? min(hornSpacing, hornSpacingCandidate) : 0
        let effectiveLegSpacing = legsEnabled ? min(legSpacing, legSpacingCandidate) : 0

        let leftHornStart = left + radius + effectiveHornSpacing
        let rightHornStart = right - radius - effectiveHornSpacing - effectiveHornWidth

        let leftLegStart = left + radius + effectiveLegSpacing
        let rightLegStart = right - radius - effectiveLegSpacing - effectiveLegWidth

        path.move(to: CGPoint(x: left + radius, y: innerTop))
        path.addQuadCurve(to: CGPoint(x: left, y: innerTop + radius), control: CGPoint(x: left, y: innerTop))
        path.addLine(to: CGPoint(x: left, y: innerBottom - radius))
        path.addQuadCurve(to: CGPoint(x: left + radius, y: innerBottom), control: CGPoint(x: left, y: innerBottom))

        if legsEnabled {
            path.addLine(to: CGPoint(x: leftLegStart, y: innerBottom))
            path.addQuadCurve(
                to: CGPoint(x: leftLegStart + effectiveLegWidth / 2, y: innerBottom + legHeight),
                control: CGPoint(x: leftLegStart + effectiveLegWidth * 0.15, y: innerBottom + legHeight)
            )
            path.addQuadCurve(
                to: CGPoint(x: leftLegStart + effectiveLegWidth, y: innerBottom),
                control: CGPoint(x: leftLegStart + effectiveLegWidth * 0.85, y: innerBottom + legHeight)
            )

            path.addLine(to: CGPoint(x: rightLegStart, y: innerBottom))
            path.addQuadCurve(
                to: CGPoint(x: rightLegStart + effectiveLegWidth / 2, y: innerBottom + legHeight),
                control: CGPoint(x: rightLegStart + effectiveLegWidth * 0.15, y: innerBottom + legHeight)
            )
            path.addQuadCurve(
                to: CGPoint(x: rightLegStart + effectiveLegWidth, y: innerBottom),
                control: CGPoint(x: rightLegStart + effectiveLegWidth * 0.85, y: innerBottom + legHeight)
            )
        }

        path.addLine(to: CGPoint(x: right - radius, y: innerBottom))
        path.addQuadCurve(to: CGPoint(x: right, y: innerBottom - radius), control: CGPoint(x: right, y: innerBottom))
        path.addLine(to: CGPoint(x: right, y: innerTop + radius))
        path.addQuadCurve(to: CGPoint(x: right - radius, y: innerTop), control: CGPoint(x: right, y: innerTop))

        if hornsEnabled {
            let hornOutset = effectiveHornWidth * 0.45
            let hornTipY = rect.minY - hornHeight * 0.35

            // Right horn leans outward to the right
            path.addLine(to: CGPoint(x: rightHornStart + effectiveHornWidth, y: innerTop))
            path.addQuadCurve(
                to: CGPoint(x: rightHornStart + effectiveHornWidth + hornOutset, y: hornTipY),
                control: CGPoint(x: rightHornStart + effectiveHornWidth + hornOutset * 0.65, y: innerTop - hornHeight * 0.35)
            )
            path.addQuadCurve(
                to: CGPoint(x: rightHornStart, y: innerTop),
                control: CGPoint(x: rightHornStart + hornOutset * 0.25, y: innerTop - hornHeight)
            )

            // Move across the top between horns and draw the left horn leaning outward
            path.addLine(to: CGPoint(x: leftHornStart + effectiveHornWidth, y: innerTop))
            path.addQuadCurve(
                to: CGPoint(x: leftHornStart - hornOutset, y: hornTipY),
                control: CGPoint(x: leftHornStart + effectiveHornWidth - hornOutset * 0.65, y: innerTop - hornHeight * 0.35)
            )
            path.addQuadCurve(
                to: CGPoint(x: leftHornStart, y: innerTop),
                control: CGPoint(x: leftHornStart - hornOutset * 0.25, y: innerTop - hornHeight)
            )
        }

        path.addLine(to: CGPoint(x: left + radius, y: innerTop))
        path.closeSubpath()
        return path
    }
}


#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.
