import APIClient
import ComponentLibrary
import ComposableArchitecture
import FeatureHooksModels
import FeatureHooksMoreMenu
import Localization
import SwiftUI
import Utilities

public struct HooksGridScreen: View {
    @Bindable var store: StoreOf<HooksGridReducer>

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

    public var body: some View {
        content
            .stableRefreshable {
                await store.send(.pullToRefresh).finish()
            }
    }

    @ViewBuilder
    private var content: some View {
        switch store.viewState {
        case .initialLoading:
            ProgressView()
                .frame(maxWidth: .infinity, maxHeight: .infinity)

        case .empty:
            emptyView
                .frame(maxWidth: .infinity, maxHeight: .infinity)

        case .failed(let message):
            FailedView(
                title: L10n.FeatureHooks.failedToLoadClips,
                message: message,
                buttonTitle: L10n.FeaturePlaylistDetail.retry,
                action: { store.send(.internal(.loadHooks)) }
            )

        case .loaded(let hooks, let hasMore, let isLoadingMore):
            loadedView(
                hooks: hooks,
                hasMore: hasMore,
                isLoadingMore: isLoadingMore
            )
        }
    }

    @ViewBuilder
    private func loadedView(
        hooks: [Hook],
        hasMore: Bool,
        isLoadingMore: Bool
    ) -> some View {
        let thumbnailsDict = store.pendingThumbnailsDict

        ScrollView {
            LazyVGrid(
                columns: gridColumns,
                spacing: store.gridAppearance.verticalSpacing
            ) {
                ForEach(hooks, id: \.id) { hook in
                    hookCard(for: hook, thumbnailsDict: thumbnailsDict)
                }

                if hasMore, !isLoadingMore {
                    ProgressView()
                        .frame(maxWidth: .infinity)
                        .padding()
                        .gridCellColumns(store.gridAppearance.columnsPerRow)
                        .onAppear {
                            store.send(.getNextPage)
                        }
                }
            }
            .padding(.vertical, store.gridAppearance.verticalPadding)
            .padding(.horizontal, store.gridAppearance.horizontalPadding)
        }
    }

    @ViewBuilder
    private func hookCard(for hook: Hook, thumbnailsDict: [String: UIImage]) -> some View {
        let hookPostFailedStatus: Bool = hook.status == .renderedFailedModeration || hook.status == .error || hook.status == .undefined || hook.status == .failed
        HookCard(
            thumbnailUrlString: hook.thumbnailImageUrl,
            thumbnailImage: thumbnailsDict[hook.id],
            createdAt: hook.createdAt,
            clipName: hook.clip?.title,
            playCount: hook.viewCount,
            statusPillText: hookPostFailedStatus ? L10n.FeatureHooks.failedToPost : nil,
            cardTapped: {
                store.send(.hookCardTapped(hook))
            },
            moreTapped: {
                store.send(.hookMoreTapped(hook))
            },
            statusPillTapped: {
                store.send(.hookStatusPillTapped(hook))
            },
            isProcessing: hook.status == .processing,
            showUnpublishedBadge: hook.clip?.isPublic == false
        )
    }

    private var gridColumns: [GridItem] {
        Array(
            repeating: GridItem(
                .flexible(),
                spacing: store.gridAppearance.horizontalSpacing
            ),
            count: store.gridAppearance.columnsPerRow
        )
    }

    private var emptyView: some View {
        let title = switch store.emptyState {
        case .none: L10n.FeatureHooksGrid.emptyHooksTitle
        case .createFirstHook: L10n.FeatureHooksGrid.myHooksEmptyTitle
        case .noLikedHooks: L10n.FeatureHooksGrid.noLikedHooks
        }

        return NoResultsView(
            leadingView: { Image.Assets.songsEmptyState2 },
            title: nil,
            message: title,
            style: .v1,
            trailingView: {
                switch store.emptyState {
                case .none, .noLikedHooks:
                    EmptyView()
                case .createFirstHook:
                    PrimaryButtonV1(
                        title: L10n.FeatureHooksGrid.createFirstHook,
                        colorCombination: .lightAlways,
                        preferredSize: .createAHook,
                        action: {
                            store.send(.createHookTapped)
                        }
                    )
                }
            },
            horizontalPadding: 71,
            verticalPadding: 34,
            verticalSpacing: 16
        )
    }
}

private extension Array {
    func chunked(into size: Int) -> [[Element]] {
        stride(from: 0, to: count, by: size).map {
            Array(self[$0 ..< Swift.min($0 + size, count)])
        }
    }
}

private extension PillButtonSizeV1 {
    static let createAHook = PillButtonSizeV1(
        typography: .buttonText,
        width: nil,
        maxWidth: .infinity,
        minHeight: 46,
        iconWidth: 16,
        borderRadius: 40,
        padding: EdgeInsets()
    )
}

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