import ComponentLibrary
import ComposableArchitecture
import FeatureShareAssetCreation
import FeatureToasts
import Localization
import ShareAssetClient
import SwiftUI

public struct ShareSheet<S: Shareable>: View {
    @Environment(\.dismiss) private var dismiss
    @State private var haptics = false
    @Bindable private var store: StoreOf<ShareSheetReducer<S>>

    // Maintain a local state for actions so as not to inherit
    // the updated order while the sheet is presented.
    @State private var actions: [ShareableTarget]

    public init(store: StoreOf<ShareSheetReducer<S>>) {
        self.store = store

        // We copy the share actions only once.
        self.actions = store.availableActions
    }
}

// MARK: - Computed Properties
extension ShareSheet {
    private var filteredActions: [ShareableTarget] {
        guard store.item.supportsVideoRendering == false else {
            return actions
        }
        return actions.filter { $0.requiresVideoRendering == false }
    }

    private var isSystemShareSheetPresented: Binding<Bool> {
        return .init(get: {
            store.destination == .systemShareSheet
        }, set: { isPresented in
            guard !isPresented else { return }
            store.send(.dismissDestination)
        })
    }

    private var isMessageComposerPresented: Binding<Bool> {
        return .init(get: {
            store.destination == .messageComposer
        }, set: { isPresented in
            guard !isPresented else { return }
            store.send(.dismissDestination)
        })
    }
}

// MARK: - UI
extension ShareSheet {
    public var body: some View {
        VStack(spacing: 0) {
            // Header
            Toolbar(
                title: ToolbarTitle(S.sheetTitle),
                trailing: {
                    ToolbarButton(.close, background: Color.SemanticV1.backgroundTertiary) { dismiss() }
                }
            )

            Spacer()

            // Item Preview
            store.item.preview
                .padding(.init(top: 50, bottom: 25))

            Spacer()

            shareableActions
        }
        .presentationCornerRadius(40, conditional: true)
        .foregroundStyle(Color.SemanticV1.textPrimary)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .sensoryFeedbackIfEnabled(.impact, trigger: haptics)
        .toast($store.toast, position: .top)
        .onAppear {
            store.send(.onAppear)
        }
        .sheet(item: $store.scope(state: \.destination?.assetCreation, action: \.destination.assetCreation)) {
            log.debug("Dismissed Share Asset Creation Sheet")
            store.send(.dismissedAssetCreationSheet)
        } content: { store in
            AssetCreationView(store: store)
        }
        .sheet(item: $store.scope(state: \.destination?.downloadScreen, action: \.destination.downloadScreen)) {
            log.debug("Dismissed Asset Download Screen")
        } content: { store in
            AssetDownloadScreenView(store: store)
        }
        .sheet(isPresented: isSystemShareSheetPresented) {
            SystemShareSheet(item: store.effectiveShareURL)
                .presentationDetents([.medium, .large])
        }
        .sheet(isPresented: isMessageComposerPresented) {
            if let composeView = try? SMSComposeView(messageBody: store.decoratedShareString) {
                composeView
            }
        }
    }

    @ViewBuilder
    private var shareableActions: some View {
        // Share Actions
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 0) {
                ForEach(filteredActions, id: \.id) { action in
                    let canUseRenderPipeline = store.canUseVideoShareAssetPipeline

                    let button = ShareButton(config: action) {
                        haptics.toggle()
                        store.send(.share(.triggerShareActionTarget(action)), animation: .default)
                    }

                    if action.requiresVideoRendering {
                        button
                            .opacity(canUseRenderPipeline ? 1.0 : 0.5)
                            .disabled(!canUseRenderPipeline)
                    } else {
                        button
                    }
                }
            }
            .padding(.horizontal, 10)
        }
        .padding(.vertical, 20)
        .background(Color.SemanticV1.backgroundSecondary)
        .ignoresSafeArea(.container, edges: .bottom)
    }
}
