//
//  ShareHostingController.swift
//  ShareExtension
//
//  Created by Shadowfacts on 4/17/23.
//  Copyright © 2023 Shadowfacts. All rights reserved.
//

import SwiftUI
import ComposeUI
import TuskerComponents
import Combine
import TuskerPreferences

class ShareHostingController: UIHostingController<ShareHostingController.View> {
    private static func fetchAvatar(_ url: URL) async -> UIImage? {
        guard let (data, _) = try? await URLSession.shared.data(from: url),
              let image = UIImage(data: data) else {
            return nil
        }
        #if os(visionOS)
        let size: CGFloat = 50 * 2
        #else
        let size = 50 * UIScreen.main.scale
        #endif
        return await image.byPreparingThumbnail(ofSize: CGSize(width: size, height: size)) ?? image
    }
    
    private let controller: ComposeController
    
    private var mastodonContextPublisher: CurrentValueSubject<ShareMastodonContext, Never>
    private var cancellables = Set<AnyCancellable>()
    
    init(draft: Draft, mastodonContext: ShareMastodonContext) {
        let mastodonContextPublisher = CurrentValueSubject<ShareMastodonContext, Never>(mastodonContext)
        self.mastodonContextPublisher = mastodonContextPublisher
        controller = ComposeController(
            draft: draft,
            config: ComposeUIConfig(),
            mastodonController: mastodonContext,
            fetchAvatar: Self.fetchAvatar,
            fetchAttachment: { _ in fatalError("edits aren't allowed in share sheet, can't fetch existing attachment") },
            fetchStatus: { _ in fatalError("replies aren't allowed in share sheet") },
            displayNameLabel: { account, style, _ in AnyView(Text(account.displayName).font(.system(style))) },
            currentAccountContainerView: { AnyView(SwitchAccountContainerView(content: $0, mastodonContextPublisher: mastodonContextPublisher)) },
            replyContentView: { _, _  in fatalError("replies aren't allowed in share sheet") },
            emojiImageView: {
                AnyView(AsyncImage(url: $0.url) {
                    $0
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                } placeholder: {
                    Image(systemName: "smiley.fill")
                })
            }
        )
        super.init(rootView: View(controller: controller))
        
        updateConfig()
        
        mastodonContextPublisher
            .sink { [unowned self] in
                self.controller.mastodonController = $0
                self.controller.draft.accountID = $0.accountInfo!.id
            }
            .store(in: &cancellables)
        mastodonContextPublisher
            .flatMap { $0.$ownAccount }
            .sink { [unowned self] in self.controller.currentAccount = $0 }
            .store(in: &cancellables)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError()
    }
    
    private func updateConfig() {
        var config = ComposeUIConfig()
        config.allowSwitchingDrafts = false
        config.textSelectionStartsAtBeginning = true
        
        config.backgroundColor = Color(uiColor: .appBackground)
        config.groupedBackgroundColor = Color(uiColor: .appGroupedBackground)
        config.groupedCellBackgroundColor = Color(uiColor: .appGroupedCellBackground)
        config.fillColor = Color(uiColor: .appFill)
        switch Preferences.shared.avatarStyle {
        case .roundRect:
            config.avatarStyle = .roundRect
        case .circle:
            config.avatarStyle = .circle
        }
        config.useTwitterKeyboard = Preferences.shared.useTwitterKeyboard
        config.contentType = Preferences.shared.statusContentType
        config.requireAttachmentDescriptions = Preferences.shared.requireAttachmentDescriptions
        
        config.dismiss = { [unowned self] in self.dismiss(mode: $0) }
        
        controller.config = config
    }
    
    private func dismiss(mode: DismissMode) {
        guard let extensionContext else { return }
        switch mode {
        case .cancel:
            extensionContext.cancelRequest(withError: Error.cancelled)
        case .post:
            extensionContext.completeRequest(returningItems: nil)
        }
    }
    
    struct View: SwiftUI.View {
        let controller: ComposeController
        
        var body: some SwiftUI.View {
            ControllerView(controller: { controller })
        }
    }
    
    enum Error: Swift.Error {
        case cancelled
    }
}

// todo: shouldn't just copy this from the main Colors.swift
extension UIColor {
    static let appBackground = UIColor { traitCollection in
        if case .dark = traitCollection.userInterfaceStyle,
           !Preferences.shared.pureBlackDarkMode {
            return UIColor(hue: 230/360, saturation: 23/100, brightness: 10/100, alpha: 1)
        } else {
            return .systemBackground
        }
    }

    static let appGroupedBackground = UIColor { traitCollection in
        if case .dark = traitCollection.userInterfaceStyle,
           !Preferences.shared.pureBlackDarkMode {
            if traitCollection.userInterfaceLevel == .elevated {
                return UIColor(hue: 230/360, saturation: 23/100, brightness: 10/100, alpha: 1)
            } else {
                return UIColor(hue: 230/360, saturation: 23/100, brightness: 5/100, alpha: 1)
            }
        } else {
            return .systemGroupedBackground
        }
    }
    
    static let appGroupedCellBackground = UIColor { traitCollection in
        if case .dark = traitCollection.userInterfaceStyle {
            if Preferences.shared.pureBlackDarkMode {
                return .secondarySystemBackground
            } else {
                return .appFill
            }
        } else {
            return .systemBackground
        }
    }
    
    static let appFill = UIColor { traitCollection in
        if case .dark = traitCollection.userInterfaceStyle,
           !Preferences.shared.pureBlackDarkMode {
            return UIColor(hue: 230/360, saturation: 20/100, brightness: 17/100, alpha: 1)
        } else {
            return .systemFill
        }
    }
}