import UIKit
import os

// MARK: - RosettaMessageListController

/// Chat message list using custom RosettaListView (Telegram-parity).
/// Replaces NativeMessageListController (UICollectionView-based).
///
/// Phase 1: Basic message display + scroll. No keyboard, date pills, selection.
@MainActor
final class RosettaMessageListController: UIViewController {

    private static let perfLog = Logger(subsystem: "com.rosetta.messenger", category: "RosettaList")

    // MARK: - Configuration

    struct Config {
        var maxBubbleWidth: CGFloat
        var currentPublicKey: String
        var opponentPublicKey: String
        var opponentTitle: String
        var isGroupChat: Bool
        var groupAdminKey: String
        var actions: MessageCellActions
    }

    private let config: Config

    // MARK: - Callbacks (mirrors NativeMessageListController API)

    var onScrollToBottomVisibilityChange: ((Bool) -> Void)?
    var onPaginationTrigger: (() -> Void)?
    var onBottomPaginationTrigger: (() -> Void)?
    var onJumpToBottom: (() -> Void)?
    var onTapBackground: (() -> Void)?
    var onComposerHeightChange: ((CGFloat) -> Void)?
    var onKeyboardDidHide: (() -> Void)?
    var onComposerSend: (() -> Void)?
    var onComposerAttach: (() -> Void)?
    var onComposerTextChange: ((String) -> Void)?
    var onComposerFocusChange: ((Bool) -> Void)?
    var onComposerReplyCancel: (() -> Void)?
    var onComposerForwardCancel: (() -> Void)?
    var onComposerTyping: (() -> Void)?

    // MARK: - Public State

    var hasMoreMessages: Bool = true
    var hasNewerMessages: Bool = false

    // MARK: - Composer

    private(set) var composerView: ComposerView?

    // MARK: - Views

    private let listView = RosettaListView(frame: .zero)

    // MARK: - State

    private var messages: [ChatMessage] = []
    private var layoutCache: [String: MessageCellLayout] = [:]
    private var textLayoutCache: [String: CoreTextTextLayout] = [:]

    // MARK: - Init

    init(config: Config) {
        self.config = config
        super.init(nibName: nil, bundle: nil)
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) { fatalError() }

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .clear

        listView.frame = view.bounds
        listView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        listView.stackFromBottom = true
        view.addSubview(listView)

        // Wire listView callbacks
        listView.onTapBackground = { [weak self] in
            self?.onTapBackground?()
        }
        listView.displayedItemRangeChanged = { [weak self] range in
            guard let self, let range else { return }
            // Pagination: load more when near top
            if range.lowerBound <= 5, self.hasMoreMessages {
                self.onPaginationTrigger?()
            }
            // Reverse pagination: load newer when near bottom
            if range.upperBound >= self.messages.count - 5, self.hasNewerMessages {
                self.onBottomPaginationTrigger?()
            }
        }
        listView.onScroll = { [weak self] _, _ in
            // TODO: scroll-to-bottom button visibility
        }
    }

    /// Setup composer view (called externally after init).
    /// TODO: Full composer integration — currently NativeMessageListController handles this.
    func setupComposer() {
        // Composer setup is complex (voice recording, attachments, reply bar, etc.)
        // Will be ported from NativeMessageListController in a later phase.
    }

    // MARK: - Selection Mode (stub)

    func setSelectionMode(_ enabled: Bool, animated: Bool) {
        // TODO: implement selection mode
    }

    func updateSelectedIds(_ ids: Set<String>) {
        // TODO: implement selection
    }

    // MARK: - Highlight (stub)

    func scrollToMessage(id: String, animated: Bool) {
        listView.scrollToItem(id: id, animated: animated)
    }

    func animateHighlight(messageId: String?) {
        // TODO: implement highlight
    }

    // MARK: - Empty State (stub)

    func updateEmptyState(isEmpty: Bool, info: Any?) {
        // TODO: implement empty state
    }

    // MARK: - Public API

    /// Update displayed messages. Calculates layouts and builds list items.
    func update(messages: [ChatMessage]) {
        let start = CACurrentMediaTime()
        self.messages = messages

        // Calculate layouts for new messages (reuse cached)
        calculateLayouts()

        // Build list items
        var items: [RosettaListItem] = []
        for message in messages {
            guard let layout = layoutCache[message.id] else { continue }
            let textLayout = textLayoutCache[message.id]
            let item = ChatMessageListItem(
                message: message,
                layout: layout,
                textLayout: textLayout,
                timestampText: formatTimestamp(message.timestamp),
                actions: config.actions
            )
            items.append(item)
        }

        listView.setItems(items)

        let ms = (CACurrentMediaTime() - start) * 1000
        Self.perfLog.notice("⚡ RosettaList.update: \(messages.count, privacy: .public) msgs in \(String(format: "%.0f", ms), privacy: .public)ms")
    }

    /// Scroll to newest message.
    func scrollToBottom(animated: Bool) {
        listView.scrollToBottom(animated: animated)
    }

    // MARK: - Layout Calculation

    private func calculateLayouts() {
        let isDark = traitCollection.userInterfaceStyle == .dark
        let (layouts, textLayouts) = MessageCellLayout.batchCalculate(
            messages: messages,
            maxBubbleWidth: config.maxBubbleWidth,
            currentPublicKey: config.currentPublicKey,
            opponentPublicKey: config.opponentPublicKey,
            opponentTitle: config.opponentTitle,
            isGroupChat: config.isGroupChat,
            groupAdminKey: config.groupAdminKey,
            isDarkMode: isDark,
            dirtyIds: nil,
            existingLayouts: layoutCache.isEmpty ? nil : layoutCache,
            existingTextLayouts: textLayoutCache.isEmpty ? nil : textLayoutCache
        )
        layoutCache = layouts
        textLayoutCache = textLayouts
    }

    // MARK: - Timestamp Formatting

    private static let timestampFormatter: DateFormatter = {
        let f = DateFormatter()
        f.dateFormat = "HH:mm"
        f.locale = .autoupdatingCurrent
        f.timeZone = .autoupdatingCurrent
        return f
    }()

    private func formatTimestamp(_ ms: Int64) -> String {
        Self.timestampFormatter.string(from: Date(timeIntervalSince1970: Double(ms) / 1000))
    }
}
