import APIClient
import AnalyticsClient
import ComponentLibrary
import ComposableArchitecture
import FeatureBrandedAlert
import FeatureToasts
import Foundation
import Localization
import SwiftUI
import Utilities

public struct HooksPostScreen: View {
    @Bindable public var store: StoreOf<HooksPostScreenReducer>
    @FocusState private var isCaptionFocused: Bool
    private let captionTextFieldHeight: CGFloat = 100
    @Namespace private var previewAnimation

    @Dependency(\.analyticsClient) var analyticsClient

    public init(store: StoreOf<HooksPostScreenReducer>) {
        self.store = store
    }

    public var body: some View {
        contentWithOverlays
            .sheet(
                item: $store.scope(
                    state: \.destination?.publishSongPopUp,
                    action: \.destination.publishSongPopUp
                )
            ) { _ in
                publishSongPopUpView
            }
            .animation(.spring(response: 0.7, dampingFraction: 0.85), value: store.destination?.fullscreenPreview != nil)
            .environment(\.colorScheme, .dark)
            .toast(
                $store.toast,
                position: .top,
                padding: EdgeInsets(top: 24, leading: 16, bottom: 0, trailing: 16)
            )
            .task {
                store.send(.task)
            }
    }

    @ViewBuilder
    private var contentWithOverlays: some View {
        mainContent
            .overlay {
                postButton
            }
            .overlay {
                if let alertStore = store.scope(state: \.destination?.brandedAlert, action: \.destination.brandedAlert) {
                    BrandedAlertView(alertStore)
                }
            }
            .overlay {
                fullscreenPreviewOverlay
            }
    }

    @ViewBuilder
    private var mainContent: some View {
        VStack(spacing: 0) {
            toolbar
            ScrollViewReader { proxy in
                ScrollView {
                    hookPreview

                    captionTextField
                        .padding(.bottom, 22)

                    VStack(spacing: 16) {
                        Divider()
                        
                        showLyricsOptionRow
                        
                        Divider()
                        
                        allowCommentsOptionRow
                    }
                    .padding(.horizontal, 12)

                    Color.clear
                        .frame(height: 1)
                        .id("captionFieldAnchor")
                        .padding(.bottom, captionTextFieldHeight)
                }
                .scrollDismissesKeyboard(.interactively)
                .scrollIndicators(.hidden)
                .onChange(of: isCaptionFocused) { _, isFocused in
                    if isFocused {
                        trackAnalytics(actionName: .captionFieldFocused)
                        withAnimation {
                            proxy.scrollTo("captionFieldAnchor", anchor: .bottom)
                        }
                    } else {
                        trackAnalytics(actionName: .captionFieldUnfocused)
                    }
                }
            }
            .presentationDragIndicator(.hidden)
        }
        .onTapGesture { self.dismissKeyboard() }
    }

    @ViewBuilder
    private var publishSongPopUpView: some View {
        if let clip = store.clip {
            PublishSongPopUp(
                clip: clip,
                publishAction: {
                    store.send(.publishClipTapped)
                },
                dismissAction: {
                    store.send(.dismissPublishClipPopUp)
                },
                isPublishing: store.isPublishingSong
            )
            .presentationDragIndicator(.visible)
            .presentationCornerRadius(30, conditional: true)
            .presentationBackground(Color.SemanticV1.backgroundSecondary)
            .environment(\.colorScheme, .dark)
        }
    }

    @ViewBuilder
    private var toolbar: some View {
        Text(L10n.FeatureHooks.postTitle)
            .typographyV1(.headline4.size { _ in 16.0 }.lineHeight(20.0))
            .frame(maxWidth: .infinity, alignment: .center)
            .overlay(alignment: .leading) {
                ZStack {
                    Circle()
                        .fill(Color.SemanticV1.backgroundSecondary)
                        .frame(width: 40, height: 40)

                    Button {
                        isCaptionFocused = false
                        store.send(.backTapped)
                    } label: {
                        Image.Icon.backButtonV1
                            .resizable()
                            .foregroundColor(.SemanticV1.iconPrimary)
                            .frame(width: 24, height: 24)
                    }
                }
            }
            .overlay(alignment: .trailing) {
                if isCaptionFocused {
                    Button {
                        isCaptionFocused = false
                        store.send(.doneTapped)
                    } label: {
                        Text(L10n.FeatureHooks.done)
                            .typographyV1(.headline4.size { _ in 16.0 }.lineHeight(20.0))
                            .multilineTextAlignment(.center)
                            .foregroundStyle(Color.SemanticV1.backgroundPrimary)
                            .padding(.horizontal, 16)
                            .padding(.vertical, 8)
                            .background(Color.SemanticV1.textPrimary)
                            .cornerRadius(60)
                    }
                }
            }
            .animation(.easeInOut(duration: 0.1), value: isCaptionFocused)
            .padding(.horizontal, 12)
            .padding(.top, 8)
            .padding(.bottom, 16)
    }

    @ViewBuilder
    private var hookPreview: some View {
        let previewHeight: CGFloat = 0.44 * UIScreen.height
        let previewWidth: CGFloat = 0.53 * UIScreen.width
        HooksPostVideoPreview(
            localVideoURL: store.localVideoURL,
            isVideoPlaying: Binding(
                get: { store.isVideoPlaying },
                set: { store.send(.setVideoPlaying($0)) }
            ),
            isLoadingClip: store.isLoadingForPreviewTap,
            didTapPreview: {
                isCaptionFocused = false
                store.send(.previewTapped)
            },
            restartTrigger: store.videoRestartTrigger
        )
        .cornerRadius(30)
        .frame(width: previewWidth, height: previewHeight)
        .padding(.bottom, 24)
        .matchedGeometryEffect(id: "videoPreview", in: previewAnimation)
    }

    @ViewBuilder
    private var captionTextField: some View {
        CaptionTextField(
            caption: Binding(
                get: { store.caption },
                set: { store.send(.captionEdited($0)) }
            ),
            isFocused: $isCaptionFocused,
            placeHolderText: "\(L10n.FeatureHooks.addCaption)...",
            characterLimit: 500
        )
        .frame(height: captionTextFieldHeight)
        .padding(.horizontal, 16)
    }

    @ViewBuilder
    private var allowCommentsOptionRow: some View {
        HookPostOptionToggleRow(
            icon: Image.Icon.comment,
            titleText: L10n.FeatureClipDetail.allowComments,
            isOn: $store.allowComments,
            onToggle: { store.send(.allowCommentsToggled($0)) }
        )
    }

    @ViewBuilder
    private var showLyricsOptionRow: some View {
        if store.snippetVolumeLevel > 0 {
            HookPostOptionToggleRow(
                icon: Image.Icon.lyrics,
                titleText: L10n.FeatureHooks.showLyrics,
                tooltipText: L10n.FeatureHooks.showLyricsTooltip,
                isOn: $store.showLyrics,
                onToggle: { store.send(.showLyricsToggled($0)) },
                onTooltipTapped: { store.send(.showLyricsTooltipTapped) },
                showTooltip: $store.showLyricsTooltip
            )
        }
    }

    @ViewBuilder
    private var postButton: some View {
        VStack {
            Spacer()
            Button {
                isCaptionFocused = false
                store.send(.postHookTapped)
            } label: {
                Text(L10n.FeatureHooks.post)
                    .typographyV1(.postText)
                    .foregroundColor(.SemanticV1.backgroundPrimary)
                    .padding(11)
                    .frame(maxWidth: .infinity)
                    .background(Color.SemanticV1.textPrimary)
                    .cornerRadius(40)
            }
            .padding(.horizontal, 16)
        }
        .ignoresSafeArea(.keyboard)
    }

    @ViewBuilder
    private var fullscreenPreviewOverlay: some View {
        if let fullscreenStore = store.scope(state: \.destination?.fullscreenPreview, action: \.destination.fullscreenPreview) {
            HooksPostFullscreenPreview(
                store: fullscreenStore,
                previewAnimationNamespace: previewAnimation
            )
            .transition(.asymmetric(
                insertion: .opacity
                    .animation(.easeInOut(duration: 0.4)),
                removal: .opacity
                    .animation(.easeInOut(duration: 0.3))
            ))
        }
    }
    
    private func trackAnalytics(actionName: Event.ActionName) {
        analyticsClient.trackV2(
            event: Event(
                category: .hooksPost,
                actionName: actionName,
                actionType: .tap,
                elementType: .textField,
                elementId: store.clipId.remoteId,
                context: HooksPostAnalyticsContext.createContext(
                    videoId: store.localVideoURL?.absoluteString,
                    clipId: store.clipId.remoteId,
                    caption: store.caption,
                    showLyricsEnabled: store.showLyrics,
                    allowCommentsEnabled: store.allowComments
                )
            ),
            source: "hooks_post"
        )
    }
}

private struct HookPostOptionToggleRow: View {
    let icon: Image
    let titleText: String
    let tooltipText: String?
    @Binding var isOn: Bool
    let onToggle: (Bool) -> Void
    let onTooltipTapped: (() -> Void)?
    @Binding var showTooltip: Bool

    init(
        icon: Image,
        titleText: String,
        tooltipText: String? = nil,
        isOn: Binding<Bool>,
        onToggle: @escaping (Bool) -> Void,
        onTooltipTapped: (() -> Void)? = nil,
        showTooltip: Binding<Bool> = .constant(false)
    ) {
        self.icon = icon
        self.titleText = titleText
        self.tooltipText = tooltipText
        self._isOn = isOn
        self.onToggle = onToggle
        self.onTooltipTapped = onTooltipTapped
        self._showTooltip = showTooltip
    }

    var body: some View {
        HStack(spacing: 12) {
            icon
                .resizable()
                .frame(width: 24, height: 24)
                .foregroundStyle(Color.SemanticV2.foregroundPrimary)

            HStack(spacing: 4) {
                Text(titleText)
                    .foregroundStyle(Color.SemanticV2.foregroundPrimary)
                    .typographyV1(.body1.lineHeight(0))
                    .lineLimit(1)

                if let tooltipText = tooltipText {
                    toolTipButton(text: tooltipText)
                }

                Spacer()
            }

            Spacer()

            Toggle(isOn: Binding(
                get: { isOn },
                set: onToggle
            )) {}
                .tint(Color.SemanticV2.accentBrand)
                .labelsHidden()
        }
    }

    @ViewBuilder
    private func toolTipButton(text: String) -> some View {
        Button {
            onTooltipTapped?()
        } label: {
            Image.Icon.helpFilled
                .resizable()
                .renderingMode(.template)
                .frame(width: 16, height: 16)
                .contentShape(.rect)
                .foregroundStyle(Color.SemanticV2.foregroundInactive)
        }
        .buttonStyle(.plain)
        .popover(isPresented: $showTooltip) {
            Text(text)
                .typographyV1(.caption)
                .foregroundStyle(Color.SemanticV1.textPrimary)
                .multilineTextAlignment(.leading)
                .padding(10)
                .presentationBackground(Color.SemanticV1.alwaysGrey4)
                .presentationCompactAdaptation(.popover)
                .environment(\.colorScheme, .dark)
        }
    }
}

private struct HooksPostOptionRow: View {
    let leadingIcon: Image?
    let rowText: String
    let trailingIcon: Image?
    let action: () -> Void

    init(leadingIcon: Image?, rowText: String, trailingIcon: Image?, action: @escaping () -> Void) {
        self.leadingIcon = leadingIcon
        self.rowText = rowText
        self.trailingIcon = trailingIcon
        self.action = action
    }

    var body: some View {
        VStack(spacing: 0) {
            Button {
                action()
            } label: {
                HStack(spacing: 12) {
                    if let leadingIcon = leadingIcon {
                        leadingIcon
                            .resizable()
                            .frame(width: 24, height: 24)
                            .foregroundStyle(Color.SemanticV1.iconPrimary)
                    }

                    Text(rowText)
                        .typographyV1(.body3)
                        .foregroundStyle(Color.SemanticV1.textPrimary)

                    Spacer()

                    if let trailingIcon = trailingIcon {
                        trailingIcon
                            .renderingMode(.template)
                            .resizable()
                            .frame(width: 24, height: 24)
                            .foregroundColor(Color.SemanticV1.foregroundInactive)
                    }
                }
                .padding(.vertical, 16)
            }
            Divider()
        }
    }
}

private extension TypographyV1 {
    static let postText: TypographyV1 = .init(
        name: "Post Text",
        size: 16,
        style: .body,
        weight: .neueMontrealMedium,
        lineHeight: 24
    )
}
