import DesignSystem
import Env
import Models
import Network
import NukeUI
import SwiftUI

@MainActor
public struct ConversationDetailView: View {
  private enum Constants {
    static let bottomAnchor = "bottom"
  }

  @Environment(QuickLook.self) private var quickLook
  @Environment(RouterPath.self) private var routerPath
  @Environment(CurrentAccount.self) private var currentAccount
  @Environment(Client.self) private var client
  @Environment(Theme.self) private var theme
  @Environment(StreamWatcher.self) private var watcher

  @State private var viewModel: ConversationDetailViewModel

  @FocusState private var isMessageFieldFocused: Bool

  @State private var scrollProxy: ScrollViewProxy?
  @State private var didAppear: Bool = false

  public init(conversation: Conversation) {
    _viewModel = .init(initialValue: .init(conversation: conversation))
  }

  public var body: some View {
    ScrollViewReader { proxy in
      ScrollView {
        LazyVStack {
          if viewModel.isLoadingMessages {
            loadingView
          }
          ForEach(viewModel.messages) { message in
            ConversationMessageView(message: message,
                                    conversation: viewModel.conversation)
              .padding(.vertical, 4)
              .id(message.id)
          }
          bottomAnchorView
        }
        .padding(.horizontal, .layoutPadding)
      }
      #if !os(visionOS)
      .scrollDismissesKeyboard(.interactively)
      #endif
      .safeAreaInset(edge: .bottom) {
        inputTextView
      }
      .onAppear {
        scrollProxy = proxy
        viewModel.client = client
        isMessageFieldFocused = true
        if !didAppear {
          didAppear = true
          Task {
            await viewModel.fetchMessages()
            DispatchQueue.main.async {
              withAnimation {
                proxy.scrollTo(Constants.bottomAnchor, anchor: .bottom)
              }
            }
          }
        }
      }
    }
    .navigationBarTitleDisplayMode(.inline)
    #if !os(visionOS)
    .scrollContentBackground(.hidden)
    .background(theme.primaryBackgroundColor)
    #endif
    .toolbar {
      ToolbarItem(placement: .principal) {
        if viewModel.conversation.accounts.count == 1,
           let account = viewModel.conversation.accounts.first
        {
          EmojiTextApp(.init(stringValue: account.safeDisplayName), emojis: account.emojis)
            .font(.scaledHeadline)
            .foregroundColor(theme.labelColor)
            .emojiSize(Font.scaledHeadlineFont.emojiSize)
            .emojiBaselineOffset(Font.scaledHeadlineFont.emojiBaselineOffset)
        } else {
          Text("Direct message with \(viewModel.conversation.accounts.count) people")
            .font(.scaledHeadline)
        }
      }
    }
    .onChange(of: watcher.latestEvent?.id) {
      if let latestEvent = watcher.latestEvent {
        viewModel.handleEvent(event: latestEvent)
        DispatchQueue.main.async {
          withAnimation {
            scrollProxy?.scrollTo(Constants.bottomAnchor, anchor: .bottom)
          }
        }
      }
    }
  }

  private var loadingView: some View {
    ForEach(Status.placeholders()) { message in
      ConversationMessageView(message: message, conversation: viewModel.conversation)
        .redacted(reason: .placeholder)
        .allowsHitTesting(false)
        .padding(.vertical, 4)
    }
  }

  private var bottomAnchorView: some View {
    Rectangle()
      .fill(Color.clear)
      .frame(height: 40)
      .id(Constants.bottomAnchor)
      .accessibilityHidden(true)
  }

  private var inputTextView: some View {
    VStack {
      HStack(alignment: .bottom, spacing: 8) {
        if viewModel.conversation.lastStatus != nil {
          Button {
            routerPath.presentedSheet = .replyToStatusEditor(status: viewModel.conversation.lastStatus!)
          } label: {
            Image(systemName: "plus")
          }
          .padding(.bottom, 7)
        }

        TextField("conversations.new.message.placeholder", text: $viewModel.newMessageText, axis: .vertical)
          .focused($isMessageFieldFocused)
          .keyboardType(.default)
          .backgroundStyle(.thickMaterial)
          .padding(6)
          .overlay(
            RoundedRectangle(cornerRadius: 14)
              .stroke(.gray, lineWidth: 1)
          )
          .font(.scaledBody)
        if !viewModel.newMessageText.isEmpty {
          Button {
            Task {
              guard !viewModel.isSendingMessage else { return }
              await viewModel.postMessage()
            }
          } label: {
            if viewModel.isSendingMessage {
              ProgressView()
            } else {
              Image(systemName: "paperplane")
            }
          }
          .keyboardShortcut(.return, modifiers: .command)
          .padding(.bottom, 6)
        }
      }
      .padding(8)
    }
    .background(.thinMaterial)
  }
}
