//
//  ChatView.swift
//  damus
//
//  Created by William Casarin on 2022-04-19.
//

import SwiftUI
import EmojiKit
import EmojiPicker
import SwipeActions

fileprivate let CORNER_RADIUS: CGFloat = 10

struct ChatEventView: View {
    // MARK: Parameters
    let event: NostrEvent
    let selected_event: NostrEvent
    let prev_ev: NostrEvent?
    let next_ev: NostrEvent?
    let damus_state: DamusState
    var thread: ThreadModel
    let scroll_to_event: ((_ id: NoteId) -> Void)?
    let focus_event: (() -> Void)?
    let highlight_bubble: Bool
    
    // MARK: long-press reaction control objects
    /// Whether the user is actively pressing the view
    @State var is_pressing = false
    @State var popover_state: PopoverState = .closed {
        didSet {
            let generator = UIImpactFeedbackGenerator(style: popover_state.some_sheet_open() ? .heavy : .light)
            generator.impactOccurred()
        }
    }
    @State var selected_emoji: Emoji?

    @State private var isOnTopHalfOfScreen: Bool = false
    @StateObject private var bar: ActionBarModel
    @Environment(\.swipeViewGroupSelection) var swipeViewGroupSelection
    
    init(event: NostrEvent, selected_event: NostrEvent, prev_ev: NostrEvent?, next_ev: NostrEvent?, damus_state: DamusState, thread: ThreadModel, scroll_to_event: ((_ id: NoteId) -> Void)?, focus_event: (() -> Void)?, highlight_bubble: Bool) {
        self.event = event
        self.selected_event = selected_event
        self.prev_ev = prev_ev
        self.next_ev = next_ev
        self.damus_state = damus_state
        self.thread = thread
        self.scroll_to_event = scroll_to_event
        self.focus_event = focus_event
        self.highlight_bubble = highlight_bubble
        
        // Initialize @StateObject using wrappedValue
        _bar = StateObject(wrappedValue: make_actionbar_model(ev: event.id, damus: damus_state))
    }
    
    enum PopoverState: String {
        case closed
        case open_emoji_selector
        case open_zap_sheet

        func some_sheet_open() -> Bool {
            return self == .open_zap_sheet || self == .open_emoji_selector
        }
    }

    var just_started: Bool {
        return prev_ev == nil || prev_ev!.pubkey != event.pubkey
    }

    func next_replies_to_this() -> Bool {
        guard let next = next_ev else {
            return false
        }

        return damus_state.events.replies.lookup(next.id) != nil
    }

    func is_reply_to_prev(ref_id: NoteId) -> Bool {
        guard let prev = prev_ev else {
            return true
        }

        if let rep = damus_state.events.replies.lookup(event.id) {
            return rep.contains(prev.id)
        }

        return false
    }

    var disable_animation: Bool {
        self.damus_state.settings.disable_animation
    }

    var reply_quote_options: EventViewOptions {
        return [.no_previews, .no_action_bar, .truncate_content_very_short, .no_show_more, .no_translate, .no_media]
    }
    
    var profile_picture_view: some View {
        VStack {
            ProfilePicView(pubkey: event.pubkey, size: 32, highlight: .none, profiles: damus_state.profiles, disable_animation: disable_animation, damusState: damus_state)
                .onTapGesture {
                    show_profile_action_sheet_if_enabled(damus_state: damus_state, pubkey: event.pubkey)
                }
        }
        .frame(maxWidth: 32)
    }
    
    var by_other_user: Bool {
        return event.pubkey != damus_state.pubkey
    }

    var is_ours: Bool { return !by_other_user }

    // MARK: Zapping properties

    var lnurl: String? {
        try? damus_state.profiles.lookup_lnurl(event.pubkey)
    }
    var zap_target: ZapTarget {
        ZapTarget.note(id: event.id, author: event.pubkey)
    }

    // MARK: Views

    var event_bubble: some View {
        ChatBubble(
            direction: is_ours ? .right : .left,
            stroke_content: Color.accentColor.opacity(highlight_bubble ? 1 : 0),
            stroke_style: .init(lineWidth: 4),
            background_style: by_other_user ? DamusColors.adaptableGrey : DamusColors.adaptablePurpleBackground
        ) {
            VStack(alignment: .leading, spacing: 4) {
                if by_other_user {
                    HStack {
                        ProfileName(pubkey: event.pubkey, damus: damus_state)
                            .onTapGesture {
                                show_profile_action_sheet_if_enabled(damus_state: damus_state, pubkey: event.pubkey)
                            }
                            .lineLimit(1)
                        Text(verbatim: "\(format_relative_time(event.created_at))")
                            .foregroundColor(.gray)
                    }
                }
                
                if let reply_ref = event.direct_reply_ref(),
                   reply_ref.note_id != selected_event.id {
                    ReplyQuoteView(keypair: damus_state.keypair, quoter: event, event_id: reply_ref.note_id, state: damus_state, thread: thread, options: reply_quote_options, relayHint: reply_ref.relay)
                        .background(is_ours ? DamusColors.adaptablePurpleBackground2 : DamusColors.adaptableGrey2)
                        .foregroundColor(is_ours ? Color.damusAdaptablePurpleForeground : Color.damusAdaptableBlack)
                        .cornerRadius(5)
                        .onTapGesture {
                            self.scroll_to_event?(reply_ref.note_id)
                        }
                }
                
                let blur_images = should_blur_images(settings: damus_state.settings, contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey)
                NoteContentView(damus_state: damus_state, event: event, blur_images: blur_images, size: .normal, options: [.truncate_content])
                    .padding(2)
                if let mention = first_eref_mention_with_hints(ndb: damus_state.ndb, ev: event, keypair: damus_state.keypair) {
                    MentionView(damus_state: damus_state, mention: .note(mention.noteId, index: mention.index), relayHints: mention.relayHints)
                        .background(DamusColors.adaptableWhite)
                        .clipShape(RoundedRectangle(cornerSize: CGSize(width: 10, height: 10)))
                }
            }
            .frame(minWidth: 5, alignment: is_ours ? .trailing : .leading)
            .padding(10)
        }
        .tint(Color.accentColor)
        .overlay(
            ZStack(alignment: is_ours ? .bottomLeading : .bottomTrailing) {
                VStack {
                    Spacer()
                    self.action_bar
                        .padding(.horizontal, 5)
                }
            }
        )
        .onTapGesture {
            if popover_state == .closed {
                focus_event?()
            }
            else {
                popover_state = .closed
                let generator = UIImpactFeedbackGenerator(style: .light)
                generator.impactOccurred()
            }
        }
    }
    
    var event_bubble_with_long_press_interaction: some View {
        ZStack(alignment: is_ours ? .bottomLeading : .bottomTrailing) {
            self.event_bubble
                .sheet(isPresented: Binding(get: { popover_state == .open_emoji_selector }, set: { new_state in
                    withAnimation(new_state == true ? .easeIn(duration: 0.5) : .easeOut(duration: 0.1)) {
                        popover_state = new_state == true ? .open_emoji_selector : .closed
                    }
                })) {
                    NavigationView {
                        EmojiPickerView(selectedEmoji: $selected_emoji, emojiProvider: damus_state.emoji_provider)
                    }.presentationDetents([.medium, .large])
                }
                .sheet(isPresented: Binding(get: { popover_state == .open_zap_sheet }, set: { new_state in
                    withAnimation(new_state == true ? .easeIn(duration: 0.5) : .easeOut(duration: 0.1)) {
                        popover_state = new_state == true ? .open_zap_sheet : .closed
                    }
                })) {
                    ZapSheetViewIfPossible(damus_state: damus_state, target: zap_target, lnurl: lnurl)
                        .presentationDetents([.medium, .large])
                }
                .onChange(of: selected_emoji) { newSelectedEmoji in
                    if let newSelectedEmoji {
                        Task {
                            await send_like(emoji: newSelectedEmoji.value)
                            popover_state = .closed
                        }
                    }
                }
        }
        .scaleEffect(self.popover_state.some_sheet_open() ? 1.08 : is_pressing ? 1.02 : 1)
        .shadow(color: (is_pressing || self.popover_state.some_sheet_open()) ? .black.opacity(0.1) : .black.opacity(0.3), radius: (is_pressing || self.popover_state.some_sheet_open()) ? 8 : 0, y: (is_pressing || self.popover_state.some_sheet_open()) ? 15 : 0)
        .onLongPressGesture(minimumDuration: 0.5, maximumDistance: 10, perform: {
            withAnimation(.bouncy(duration: 0.2, extraBounce: 0.35)) {
                let should_show_zap_sheet = !damus_state.settings.nozaps && damus_state.settings.onlyzaps_mode
                popover_state = should_show_zap_sheet ? .open_zap_sheet : .open_emoji_selector
            }
        }, onPressingChanged: { is_pressing in
            withAnimation(is_pressing ? .easeIn(duration: 0.5) : .easeOut(duration: 0.1)) {
                self.is_pressing = is_pressing
            }
        })
        .onChange(of: swipeViewGroupSelection.wrappedValue) { newValue in
            self.is_pressing = false
        }
        .background(
            GeometryReader { geometry in
                EmptyView()
                    .onAppear {
                        let eventActionBarY = geometry.frame(in: .global).midY
                        let screenMidY = UIScreen.main.bounds.midY
                        self.isOnTopHalfOfScreen = eventActionBarY > screenMidY
                    }
                    .onChange(of: geometry.frame(in: .global).midY) { newY in
                        let screenMidY = UIScreen.main.bounds.midY
                        self.isOnTopHalfOfScreen = newY > screenMidY
                    }
            }
        )
    }
    
    func send_like(emoji: String) async {
        guard let keypair = damus_state.keypair.to_full(),
              let like_ev = make_like_event(keypair: keypair, liked: event, content: emoji, relayURL: await damus_state.nostrNetwork.relaysForEvent(event: event).first) else {
            return
        }

        self.bar.our_like = like_ev

        let generator = UIImpactFeedbackGenerator(style: .medium)
        generator.impactOccurred()
        
        await damus_state.nostrNetwork.postbox.send(like_ev)
    }
    
    var action_bar: some View {
        return Group {
            if !bar.is_empty {
                HStack {
                    if by_other_user {
                        Spacer()
                    }
                    EventActionBar(damus_state: damus_state, event: event, bar: bar, options: [.no_spread, .hide_items_without_activity])
                        .padding(10)
                        .background(DamusColors.adaptableLighterGrey)
                        .disabled(true)
                        .cornerRadius(100)
                        .overlay(RoundedRectangle(cornerSize: CGSize(width: 100, height: 100)).stroke(DamusColors.adaptableWhite, lineWidth: 1))
                        .shadow(color: Color.black.opacity(0.05),radius: 3, y: 3)
                        .scaleEffect(0.7, anchor: is_ours ? .leading : .trailing)
                    if !by_other_user {
                        Spacer()
                    }
                }
                .padding(.vertical, -20)
            }
        }
    }
    
    var event_bubble_with_long_press_and_swipe_interactions: some View {
        Group {
            SwipeView {
                self.event_bubble_with_long_press_interaction
            } leadingActions: { context in
                if !is_ours {
                    EventActionBar(
                        damus_state: damus_state,
                        event: event,
                        bar: bar,
                        options: is_ours ? [.swipe_action_menu_reverse] : [.swipe_action_menu],
                        swipe_context: context
                    )
                }
            } trailingActions: { context in
                if is_ours {
                    EventActionBar(
                        damus_state: damus_state,
                        event: event,
                        bar: bar,
                        options: is_ours ? [.swipe_action_menu_reverse] : [.swipe_action_menu],
                        swipe_context: context
                    )
                }
            }
            .swipeSpacing(-20)
            .swipeActionsStyle(.mask)
            .swipeMinimumDistance(40)
            .swipeDragGesturePriority(.normal)
        }
    }
    
    var content: some View {
        return VStack {
            HStack(alignment: .bottom, spacing: 4) {
                if by_other_user {
                    self.profile_picture_view
                }
                else {
                    Spacer()
                }
                
                self.event_bubble_with_long_press_and_swipe_interactions
                
                if !by_other_user {
                    self.profile_picture_view
                }
                else {
                    Spacer()
                }
            }
            .contentShape(Rectangle())
            .id(event.id)
            .padding([.bottom], bar.is_empty ? 6 : 16)
        }
    }

    var body: some View {
        if [.boost, .zap, .longform].contains(where: { event.known_kind == $0 }) {
            EmptyView()
        } else {
            self.content
        }
    }
}

#Preview {
    return ChatEventView(event: test_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: false)
}

#Preview {
    return ChatEventView(event: test_short_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: false)
}

#Preview {
    return ChatEventView(event: test_short_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: true)
}

#Preview {
    return ChatEventView(event: test_super_short_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: false)
}
