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

@MainActor
struct ConversationMessageView: View {
  @Environment(\.openWindow) private var openWindow
  @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

  let message: Status
  let conversation: Conversation

  @State private var isLiked: Bool = false
  @State private var isBookmarked: Bool = false

  var body: some View {
    let isOwnMessage = message.account.id == currentAccount.account?.id
    VStack {
      HStack(alignment: .bottom) {
        if isOwnMessage {
          Spacer()
        } else {
          AvatarView(message.account.avatar)
            .onTapGesture {
              routerPath.navigate(to: .accountDetailWithAccount(account: message.account))
            }
        }
        VStack(alignment: .leading) {
          EmojiTextApp(message.content, emojis: message.emojis)
            .font(.scaledBody)
            .foregroundColor(theme.labelColor)
            .emojiSize(Font.scaledBodyFont.emojiSize)
            .emojiBaselineOffset(Font.scaledBodyFont.emojiBaselineOffset)
            .padding(6)
            .environment(\.openURL, OpenURLAction { url in
              routerPath.handleStatus(status: message, url: url)
            })
        }
        #if os(visionOS)
        .background(isOwnMessage ? Material.ultraThick : Material.regular)
        #else
        .background(isOwnMessage ? theme.tintColor.opacity(0.2) : theme.secondaryBackgroundColor)
        #endif
        .cornerRadius(8)
        .padding(.leading, isOwnMessage ? 24 : 0)
        .padding(.trailing, isOwnMessage ? 0 : 24)
        .overlay {
          if isLiked, message.account.id != currentAccount.account?.id {
            likeView
          }
        }
        .contextMenu {
          contextMenu
        }

        if !isOwnMessage {
          Spacer()
        }
      }

      ForEach(message.mediaAttachments) { media in
        makeMediaView(media)
          .padding(.leading, isOwnMessage ? 24 : 0)
          .padding(.trailing, isOwnMessage ? 0 : 24)
      }

      if message.id == String(conversation.lastStatus?.id ?? "") {
        HStack {
          if isOwnMessage {
            Spacer()
          }
          Group {
            Text(message.createdAt.shortDateFormatted) +
              Text(" ")
            Text(message.createdAt.asDate, style: .time)
          }
          .font(.scaledFootnote)
          .foregroundStyle(.secondary)
          if !isOwnMessage {
            Spacer()
          }
        }
      }
    }
    .onAppear {
      isLiked = message.favourited == true
      isBookmarked = message.bookmarked == true
    }
  }

  @ViewBuilder
  private var contextMenu: some View {
    Button {
      routerPath.navigate(to: .statusDetail(id: message.id))
    } label: {
      Label("conversations.action.view-detail", systemImage: "arrow.forward")
    }
    Button {
      UIPasteboard.general.string = message.content.asRawText
    } label: {
      Label("status.action.copy-text", systemImage: "doc.on.doc")
    }
    Button {
      Task {
        do {
          let status: Status
          if isLiked {
            status = try await client.post(endpoint: Statuses.unfavorite(id: message.id))
          } else {
            status = try await client.post(endpoint: Statuses.favorite(id: message.id))
          }
          withAnimation {
            isLiked = status.favourited == true
          }
        } catch {}
      }
    } label: {
      Label(isLiked ? "status.action.unfavorite" : "status.action.favorite",
            systemImage: isLiked ? "star.fill" : "star")
    }
    Button { Task {
      do {
        let status: Status
        if isBookmarked {
          status = try await client.post(endpoint: Statuses.unbookmark(id: message.id))
        } else {
          status = try await client.post(endpoint: Statuses.bookmark(id: message.id))
        }
        withAnimation {
          isBookmarked = status.bookmarked == true
        }
      } catch {}
    } } label: {
      Label(isBookmarked ? "status.action.unbookmark" : "status.action.bookmark",
            systemImage: isBookmarked ? "bookmark.fill" : "bookmark")
    }
    Divider()
    if message.account.id == currentAccount.account?.id {
      Button("status.action.delete", role: .destructive) {
        Task {
          _ = try await client.delete(endpoint: Statuses.status(id: message.id))
        }
      }
    } else {
      Section(message.reblog?.account.acct ?? message.account.acct) {
        Button {
          routerPath.presentedSheet = .mentionStatusEditor(account: message.reblog?.account ?? message.account, visibility: .pub)
        } label: {
          Label("status.action.mention", systemImage: "at")
        }
      }
      Section {
        Button(role: .destructive) {
          routerPath.presentedSheet = .report(status: message.reblogAsAsStatus ?? message)
        } label: {
          Label("status.action.report", systemImage: "exclamationmark.bubble")
        }
      }
    }
  }

  private func makeImageRequest(for url: URL, size: CGSize) -> ImageRequest {
    ImageRequest(url: url, processors: [.resize(size: size)])
  }

  private func mediaWidth(proxy: GeometryProxy) -> CGFloat {
    var width = proxy.frame(in: .local).width
    if UIDevice.current.userInterfaceIdiom == .pad {
      width = width * 0.60
    }
    return width
  }

  private func makeMediaView(_ attachement: MediaAttachment) -> some View {
    GeometryReader { proxy in
      let width = mediaWidth(proxy: proxy)
      if let url = attachement.url {
        LazyImage(request: makeImageRequest(for: url,
                                            size: .init(width: width, height: 200)))
        { state in
          if let image = state.image {
            image
              .resizable()
              .aspectRatio(contentMode: .fill)
              .frame(height: 200)
              .frame(maxWidth: width)
              .clipped()
              .cornerRadius(8)
              .padding(8)
          } else if state.isLoading {
            RoundedRectangle(cornerRadius: 8)
              .fill(Color.gray)
              .frame(height: 200)
          }
        }
      }
    }
    .frame(height: 200)
    .contentShape(Rectangle())
    .onTapGesture {
#if targetEnvironment(macCatalyst)
      openWindow(value: WindowDestinationMedia.mediaViewer(attachments: [attachement],
                                                           selectedAttachment: attachement))
#else
      quickLook.prepareFor(selectedMediaAttachment: attachement, mediaAttachments: [attachement])
#endif
    }
  }

  private var likeView: some View {
    HStack {
      Spacer()
      VStack {
        Image(systemName: "star.fill")
          .foregroundColor(.yellow)
          .offset(x: -16, y: -7)
        Spacer()
      }
    }
  }
}
