import APIClient
import ComposableArchitecture
import FeatureInAppNotifications
import FeatureShareSheet
import InAppNotificationClient
import SwiftUI

@Reducer
public struct DemoAppCoordinator {
    public enum DemoFeature: String, Identifiable, Hashable, Equatable, CaseIterable {
        case inAppNotifications
        case onboardingCreate
        case notificationQuestion
        case shareSheet

        var displayName: String {
            switch self {
            case .inAppNotifications:
                return "In App Notifications"
            case .onboardingCreate:
                return "Onboarding Create"
            case .notificationQuestion:
                return "Onboarding Notification Question"
            case .shareSheet:
                return "Share Sheet"
            }
        }

        public var id: String {
            return rawValue
        }
    }

    @Reducer(state: .equatable)
    public enum Destination {
        case inAppNotifications(DemoInAppNotifications)
        case onboardingCreate(DemoOnboardingCreate)
        case onboardingNotificationQuestion(DemoOnboardingNotificationsQuestion)
        case shareSheet(ShareSheetReducer<Clip>)
    }

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

        public init() {}
    }

    public enum Action {
        case destination(PresentationAction<Destination.Action>)
        case onAppear
        case task
        case tappedFeature(DemoFeature)
        case dismissDestination
        case appDelegateDidFinishLaunching
    }

    public init() {}

    public var body: some ReducerOf<Self> {
        Reduce<State, Action> { state, action in
            switch action {
            case .onAppear:
                return .none

            case .appDelegateDidFinishLaunching:
                return .none

            case .tappedFeature(let feature):
                switch feature {
                case .inAppNotifications:
                    state.destination = .inAppNotifications(.init())
                case .onboardingCreate:
                    state.destination = .onboardingCreate(.init())
                case .notificationQuestion:
                    state.destination = .onboardingNotificationQuestion(.init())
                case .shareSheet:
                    state.destination = .shareSheet(.init(item: PreviewContent.testClip))
                }
                return .none

            case .dismissDestination:
                state.destination = nil
                return .none

            case .destination(.presented(.inAppNotifications(.dismiss))),
                 .destination(.presented(.onboardingCreate(.dismiss))),
                 .destination(.presented(.onboardingNotificationQuestion(.dismiss))):
                return .send(.dismissDestination)

            case .destination:
                return .none

            case .task:
                return .none
            }
        }
        .ifLet(\.$destination, action: \.destination)
    }
}

public struct AppCoordinatorScreen: View {
    @Bindable var store: StoreOf<DemoAppCoordinator>
    @Environment(\.scenePhase) var scenePhase

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

    public var body: some View {
        ZStack {
            List {
                ForEach(DemoAppCoordinator.DemoFeature.allCases) { id in
                    Button(id.displayName, action: {
                        store.send(.tappedFeature(id))
                    })
                }
            }
        }
        .fullScreenCover(item: $store.scope(
            state: \.destination?.inAppNotifications,
            action: \.destination.inAppNotifications
        )) { destinationStore in
            DemoInAppNotificationsView(store: destinationStore)
        }
        .fullScreenCover(item: $store.scope(
            state: \.destination?.onboardingCreate,
            action: \.destination.onboardingCreate
        )) { destinationStore in
            DemoOnboardingCreateView(store: destinationStore)
        }
        .fullScreenCover(item: $store.scope(
            state: \.destination?.onboardingNotificationQuestion,
            action: \.destination.onboardingNotificationQuestion
        )) { destinationStore in
            DemoOnboardingNotificationsQuestionView(store: destinationStore)
        }
        .sheet(item: $store.scope(
            state: \.destination?.shareSheet,
            action: \.destination.shareSheet
        )) { destinationStore in
            ShareSheet(store: destinationStore)
        }
    }
}

final class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    let store = Store(initialState: DemoAppCoordinator.State()) {
        DemoAppCoordinator()
    }

    // MARK: - Application delegate

    func application(
        _: UIApplication,
        didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool {
        store.send(.appDelegateDidFinishLaunching)
        return true
    }

    func userNotificationCenter(
        _: UNUserNotificationCenter,
        didReceive _: UNNotificationResponse,
        withCompletionHandler _: @escaping () -> Void
    ) {}

    func application(
        _: UIApplication,
        didRegisterForRemoteNotificationsWithDeviceToken _: Data
    ) {}

    func application(
        _: UIApplication,
        didFailToRegisterForRemoteNotificationsWithError _: Error
    ) {}

    func application(
        _: UIApplication,
        didReceiveRemoteNotification _: [AnyHashable: Any],
        fetchCompletionHandler _: @escaping (UIBackgroundFetchResult) -> Void
    ) {}
}

@main
struct sunoApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            AppCoordinatorScreen(store: appDelegate.store)
        }
    }
}
