import APIClient
import ComponentLibrary
import ComposableArchitecture
import FeatureToasts
import Foundation
import Localization
import SnippetPlayerClient
import SwiftUI
import Utilities

@Reducer
public struct LibraryClipPicker {
    @ObservableState
    public struct State: Equatable {
        var clips: [ClipSnippet] = []
        var selectedClipId: Clip.ID?
        var currentlyPlayingClipId: Clip.ID?
        var isPlayingCurrentClip: Bool = false
        var isLoadingMore: Bool = false
        var searchText: String = ""
        var startIndex: Int = 0
        var currentTime: Double = 0.0

        public init() {}
    }

    public enum Action {
        public enum Delegate {
            case didSelectSnippet(ClipSnippet)
            case dismiss
        }

        case task
        case fetchClips
        case fetchClipsResponse(Result<[ClipSnippet], Error>)
        case clipRowTapped(ClipSnippet)
        case clipSelectionToggled(ClipSnippet)
        case doneTapped
        case onDisappear
        case playerEvent(SnippetPlayerClientEvent)
        case reachedEndOfList
        case searchTextChanged(String)
        case delegate(Delegate)
    }

    @Dependency(\.apiClientV2) var apiClient
    @Dependency(SnippetPlayerClient.self) var playerClient
    @Dependency(\.toastClient.show) var showToast

    struct PlayerEventsSubscription: Hashable {}

    public init() {}

    public var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case .task:
                return .merge(
                    .stream(
                        playerClient.stream(),
                        send: Action.playerEvent,
                        cancellableId: PlayerEventsSubscription()
                    ),
                    .send(.fetchClips)
                )

            case .fetchClips:
                guard !state.isLoadingMore else {
                    return .none
                }

                state.isLoadingMore = true
                let startIndex = state.startIndex

                return .run { send in
                    await send(.fetchClipsResponse(
                        Result(catching: {
                            try await apiClient.getHooksSuggestedClips(
                                isLiked: false,
                                isPublicOnly: false,
                                startIndex: startIndex
                            )
                        })
                    ))
                }

            case .fetchClipsResponse(.success(let clips)):
                state.isLoadingMore = false
                state.clips.append(contentsOf: clips)
                state.startIndex += clips.count
                return .none

            case .fetchClipsResponse(.failure(let error)):
                state.isLoadingMore = false
                if let urlError = error as? URLError, urlError.code == .cancelled {
                    return .none
                }

                let toast = ToastReducer.State.ToastType.warning(
                    "Failed to load clips",
                    position: .bottom
                )
                showToast(toast)
                return .none

            case .reachedEndOfList:
                guard !state.isLoadingMore else {
                    return .none
                }
                return .send(.fetchClips)

            case .searchTextChanged(let text):
                guard state.searchText != text else {
                    return .none
                }
                state.searchText = text
                return .none

            case .clipRowTapped(let snippet):
                // Toggle play/pause for playback
                if state.currentlyPlayingClipId == snippet.clip.id {
                    state.isPlayingCurrentClip.toggle()
                    if state.isPlayingCurrentClip {
                        playerClient.playCurrentClip()
                    } else {
                        playerClient.pauseCurrentClip()
                    }
                } else {
                    state.currentlyPlayingClipId = snippet.clip.id
                    state.isPlayingCurrentClip = true
                    playerClient.loadAndPlaySnippet(snippet)
                }
                return .none

            case .clipSelectionToggled(let snippet):
                // Toggle radio button selection
                if state.selectedClipId == snippet.clip.id {
                    state.selectedClipId = nil
                } else {
                    state.selectedClipId = snippet.clip.id
                }
                return .none

            case .doneTapped:
                playerClient.pauseCurrentClip()

                // Find the selected snippet and call delegate
                if let selectedId = state.selectedClipId,
                   let selectedSnippet = state.clips.first(where: { $0.clip.id == selectedId }) {
                    return .send(.delegate(.didSelectSnippet(selectedSnippet)))
                }
                return .none

            case .onDisappear:
                playerClient.pauseCurrentClip()
                return .none

            case .playerEvent(.playbackStateChanged(.playing)),
                 .playerEvent(.playbackStateChanged(.waitingToPlayAtSpecifiedRate)):
                state.isPlayingCurrentClip = true
                return .none

            case .playerEvent(.playbackStateChanged(.paused)):
                state.isPlayingCurrentClip = false
                return .none

            case .playerEvent(.playbackTimeUpdated(currentTime: let time)):
                state.currentTime = time.seconds
                return .none

            case .playerEvent(.snippetChanged(let snippet)):
                state.currentlyPlayingClipId = snippet.clip.id
                state.isPlayingCurrentClip = true
                return .none

            case .playerEvent(.playbackStateChanged):
                return .none

            case .delegate:
                return .none
            }
        }
        Analytics()
    }
}

// MARK: - Analytics

private extension LibraryClipPicker {
    @Reducer
    struct Analytics {
        var body: some ReducerOf<LibraryClipPicker> {
            Reduce { _, action in
                switch action {
                case .task:
                    break
                case .fetchClips:
                    break
                case .fetchClipsResponse:
                    break
                case .clipRowTapped:
                    break
                case .clipSelectionToggled:
                    break
                case .doneTapped:
                    break
                case .onDisappear:
                    break
                case .playerEvent:
                    break
                case .reachedEndOfList:
                    break
                case .searchTextChanged:
                    break
                case .delegate:
                    break
                }
                return .none
            }
        }
    }
}
