import Foundation
import UIKit
import AuthenticationServices
import Combine

extension ContentService {
    static var preview: ContentService {
        ContentService(authRepository: MockAuthRepository(),
                    contentRepository: MockContentRepository(),
                    preferencesRepository: MockPreferencesRepository())
    }
}

extension UserService {
    static var preview: UserService {
        UserService(authRepository: MockAuthRepository(),
                    commentRepository: MockCommentRepository(),
                    notificationRepository: MockNotificationRepository(),
                    preferencesRepository: MockPreferencesRepository(),
                    bookmarksRepository: FirebaseBookmarksRepository.standard)
    }
}

private extension AuthResponse {
    static var mock: Self {
        AuthResponse(id: 1, name: "Stripy Sock", avatar: nil, link: "https://stripysock.com.au", email: "hello@stripysock.com.au", token: "1234", refreshToken: "5678")
    }
}

class MockAuthRepository: AuthRepository {
    var signedInState: CurrentValueSubject<SignInState, Never>
    
    func signInWithStoredToken() async {
        signedInState.send(.signedIn(response: AuthResponse.mock))
    }
    
    func signIn(presentationContextProvider: ASWebAuthenticationPresentationContextProviding) {
        signedInState.send(.signedIn(response: AuthResponse.mock))
    }
    
    func signOut() {
        signedInState.send(.signedOut)
    }
    
    func updateUserAvatar(token: String, image: UIImage) async throws -> Bool {
        throw(RiotError.dataError)
    }

    func requestDeletion(token: String) async throws -> DeleteUserResponse {
        var authResponse = AuthResponse.mock
        authResponse.deleteStatus = .pendingConfirmation
        
        signedInState.send(.signedIn(response: authResponse))
        throw(RiotError.authError)
    }
    
    func resendDeletionRequest(token: String) async throws -> DeleteUserResponse {
        var authResponse = AuthResponse.mock
        authResponse.deleteStatus = .pendingConfirmation
        
        signedInState.send(.signedIn(response: authResponse))
        throw(RiotError.authError)
    }
    
    @discardableResult
    func cancelDeletionRequest(token: String) async throws -> DeleteUserResponse {
        signedInState.send(.signedIn(response: AuthResponse.mock))
        
        throw(RiotError.authError)
    }
    
    init() {
        signedInState = .init(.signedOut)
    }
    
}

class MockContentRepository: ContentRepository {
    var policyPages: PassthroughSubject<[PolicyPage], Never>
    
    var latestPosts: PassthroughSubject<PostCollection, Never>
    
    var trendingPosts: PassthroughSubject<PostCollection, Never>
    
    var conversationPosts: PassthroughSubject<PostCollection, Never>
    
    var topics: PassthroughSubject<[Topic], Never>
    
    var searchFeatureTopics: PassthroughSubject<[Topic], Never>
    
    var events: PassthroughSubject<EventCalendar, Never>
    
    func updatePosts() async {
        //
    }
    
    func updateTopics() async {
        topics.send(Topic.previewContent)
    }
    
    func updateEvents(dateFrom: Date?, dateTo: Date?) async {
        //
    }
    
    func updatePolicyPages() async {
        //
    }
    
    func fetchPosts(for collection: Collection, pageNumber: Int?) async throws -> PostCollection {
        throw(RiotError.fetchError)
    }
    
    func fetchPostsWithIds(_ postIds: [Int], page: Int?) async throws -> PostCollection {
        throw(RiotError.fetchError)
    }
    
    func fetchPostsForTopic(_ topicId: Int, page: Int?) async throws -> PostCollection {
        throw(RiotError.fetchError)
    }
    
    func searchForPosts(_ searchTerm: String, topics: [TopicRef]) async throws -> PostCollection {
        throw(RiotError.fetchError)
    }
    
    func fetchUserComments(token: String) async throws -> Comments {
        throw(RiotError.fetchError)
    }

    func fetchAuthorDetails(_ authorId: Int, page: Int?) async throws -> AuthorResponse {
        throw(RiotError.fetchError)
    }
    
    func hydratePost(_ postId: Int) async throws -> Post {
        throw(RiotError.fetchError)
    }
    
    init() {
        latestPosts = .init()
        trendingPosts = .init()
        conversationPosts = .init()
        topics = .init()
        searchFeatureTopics = .init()
        events = .init()
        policyPages = .init()
        
        Task {
            await updatePosts()
            await updateTopics()
            await updateEvents(dateFrom: nil, dateTo: nil)
            await updatePolicyPages()
        }
    }
}

class MockCommentRepository: CommentRepository {
    func postFeedback(feedback: Feedback) async throws -> Bool {
        return true
    }
    
    func fetchUserComments(token: String) async throws -> Comments {
        throw RiotError.fetchError
    }
    
    func postReplyToComment(token: String, reply: Reply) async throws -> CommentResponse {
        throw RiotError.dataError
    }
    
    
}

class MockNotificationRepository: NotificationRepository {
    var deeplinkToOpen: PassthroughSubject<Deeplink, Never> = .init()
    
    var notificationSettings: PassthroughSubject<UNNotificationSettings, Never>
    
    var notificationReply: PassthroughSubject<Reply, Never>
    
    var token: CurrentValueSubject<String?, Never>
    
    var notificationTypeNames: NSObject.KeyValueObservingPublisher<UserDefaults, [String]?>
    
    func updateNotificationSettings() async {
        //
    }
    
    func requestNotificationPermission() async throws {
        //
    }
    
    func subscribeToNotificationTypes(_ notificationTypes: [NotificationType]) {
        //
    }
    
    func unsubscribeFromNotificationTypes(_ notificationTypes: [NotificationType]) {
        //
    }

    func savePostcode(_ postcode: String) {
        //
    }

    init() {
        notificationSettings = .init()
        notificationReply = .init()
        token = .init(nil)
        notificationTypeNames = UserDefaults.standard.publisher(for: \.subscribedTo)
    }
}

class MockPreferencesRepository: PreferencesRepository {
    
    var hasSeenOnboardingPublisher: AnyPublisher<Bool, Never> = Just(false).eraseToAnyPublisher()
    var ignoreExternalWebAssetsPublisher: AnyPublisher<Bool, Never> = Just(false).eraseToAnyPublisher()
    var ignoreAppCSSPublisher: AnyPublisher<Bool, Never> = Just(false).eraseToAnyPublisher()
    
    var ignoreExternalWebAssets: Bool = false
    var hasSeenOnboarding: Bool = true
    var ignoreAppCSS: Bool = false
    var userPostcode: Int = 2601
        
    func storeRecentSearchTerm(_ term: String) {
        print("Stored")
    }
    
    func retrieveRecentSearchTerms() -> [String] {
        return ["Mice", "Stromlo"]
    }
}
