import APIClient
import ComponentLibrary
import ComposableArchitecture
import FeatureManagePlaylist
import FeaturePlaylistDetail
import FeaturePlaylistRow
import FeatureRatingTracker
import FeatureToasts
import Localization
import SwiftUI
import Utilities

@Reducer
public struct LikedPlaylists {
    @Reducer(state: .equatable)
    public enum Destination {
        case playlistDetail(PlaylistDetail)
    }

    @ObservableState
    public struct State: Equatable {
        @Presents public var destination: Destination.State?

        @Shared var me: Me
        var rows: IdentifiedArrayOf<PlaylistRow.State> = []
        var loadState: LoadState = .loading
        var pages = PageState(firstPageIndex: 1)

        let showBackButton: Bool

        public init(me: Shared<Me>, showBackButton: Bool = true) {
            self._me = me
            self.showBackButton = showBackButton
        }
    }

    public enum Action {
        case destination(PresentationAction<Destination.Action>)

        case rows(IdentifiedActionOf<PlaylistRow>)
        case onAppear
        case getLikedPlaylists
        case getNextPage
        case dismiss
        case `internal`(Internal)

        public enum Internal {
            case playlistsResponse(_ page: Int, Result<PlaylistsResult, Error>)
        }
    }

    public init() {}

    @Dependency(\.apiClientV2) var api
    @Dependency(\.telemetryClient) var telemetry
    @Dependency(\.dismiss) var dismiss
    @Dependency(\.toastClient.show) var showToast

    public var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case .onAppear:
                return .send(.getLikedPlaylists)

            case .getLikedPlaylists:
                state.pages.reset()
                return .send(.getNextPage)

            case .getNextPage:
                guard let nextPage = state.pages.nextIndex() else { return .none }

                return .run { send in
                    await send(.internal(.playlistsResponse(nextPage, Result(catching: { try await api.getLikedPlaylists(nextPage) }))))
                }

            case .internal(.playlistsResponse(let page, .success(let playlistsResponse))):
                if page == state.pages.firstPageIndex {
                    state.rows = []
                }
                state.rows.append(contentsOf: playlistsResponse.playlists.map {
                    PlaylistRow.State(
                        playlist: $0,
                        image: .remote(url: $0.imageUrl, fallbackId: $0.id)
                    )
                })
                state.pages.update(playlistsResponse.playlists, hasAllResults: playlistsResponse.totalResults == state.rows.count)
                state.loadState = .loaded
                return .none

            case .internal(.playlistsResponse(_, .failure(let error))):
                log.telemetry.error(error)
                state.pages.update(error)
                state.loadState = .failed(L10n.FeatureClipDetail.playlistsFailed)
                showToast(ToastReducer.State.ToastType.warning(L10n.FeatureClipDetail.playlistsFailed, position: .bottom))
                return .none

            case .rows(.element(_, .delegate(.selectPlaylist(let playlist)))):
                state.destination = .playlistDetail(.init(me: state.$me, source: .playlist(playlist)))
                return .none

            case .rows:
                // Catch-all
                return .none

            case .destination:
                // Catch-all
                return .none

            case .dismiss:
                return .run { _ in await self.dismiss() }
            }
        }
        .ifLet(\.$destination, action: \.destination)
    }
}

public struct LikedPlaylistsScreen: View {
    @Bindable var store: StoreOf<LikedPlaylists>

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

    public var body: some View {
        contentView
            .navigationTitle(Text(L10n.FeatureDiscover.likedPlaylistsTitle))
            .navigationBarTitleDisplayMode(.large)
            .modifier(if: store.showBackButton) {
                $0.customBackButton(background: Material.ultraThin, action: { store.send(.dismiss) })
            }
            .background(Color.SemanticV1.backgroundPrimary)
            .onAppear {
                store.send(.onAppear)
            }
            .navigationDestination(item: $store.scope(state: \.destination?.playlistDetail, action: \.destination.playlistDetail)) { store in
                PlaylistDetailScreen(store: store)
                    .toolbar {
                        ToolbarItem(placement: .topBarLeading) {
                            ToolbarButton(.back, background: Material.ultraThin, colorScheme: store.averageColors.colorScheme) {
                                store.send(.dismiss)
                            }
                        }
                    }
            }
    }

    @ViewBuilder private var contentView: some View {
        switch store.loadState {
        case .loading:
            LoadingView()

        case .loaded:
            loadedView

        case .failed(let message):
            FailedView(
                title: L10n.FeatureDiscover.errorTitle,
                message: message,
                buttonTitle: L10n.FeatureDiscover.retry,
                action: { store.send(.getLikedPlaylists) }
            )
        }
    }

//    private func loadedView() -> some View {
//        ScrollView {
//            LazyVStack(spacing: 0) {
//                ForEach(store.scope(state: \.rows, action: \.rows)) { rowStore in
//                    Divider()
//
//                    PlaylistRowItem(store: rowStore) {
//                        EmptyView()
//                    }
//                    .contentShape(.rect)
//                }
//
//                if store.pages.hasMore {
//                    ProgressView()
//                        .progressViewStyle(.circular)
//                        .padding()
//                        .id(UUID())
//                        .onAppear {
//                            guard !store.pages.loadingNext else { return }
//                            store.send(.getNextPage)
//                        }
//                }
//            }
//        }
//    }

    private var loadedView: some View {
        List {
            if store.rows.isEmpty {
                emptyView
            } else {
                Section {
                    ForEach(store.scope(state: \.rows, action: \.rows)) { rowStore in
                        PlaylistRowItem(store: rowStore) {
                            EmptyView()
                        }
                        .contentShape(.rect)
                    }
                }
                .listRowBackground(Color.clear)
                .listSectionSeparator(.hidden, edges: .top)
                .listSectionSpacing(.zero)
                .listRowInsets(.init())
            }
        }
        .background(Color.SemanticV1.backgroundPrimary)
        .listStyle(.plain)
        .stableRefreshable { await store.send(.getLikedPlaylists).finish() }
    }

    private var emptyView: some View {
        VStack {
            Spacer()
            Text(L10n.FeatureDiscover.likedPlaylistsEmpty)
                .typographyV1(.headline4)
                .foregroundColor(Color.SemanticV1.textPrimary)
                .multilineTextAlignment(.center)
            Spacer()
        }
        .frame(maxWidth: .infinity)
        .frame(height: 100)
        .listRowSeparator(.hidden)
        .listRowBackground(Color.clear)
    }
}
