//
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation
import SignalServiceKit

extension ConversationViewController {

    public func willWrapGift(_ messageUniqueId: String) -> Bool {
        // If a gift is unwrapped at roughly the same we're reloading the
        // conversation for an unrelated reason, there's a chance we'll try to
        // re-wrap a gift that was just unwrapped. This provides an opportunity to
        // override that behavior.
        return !self.viewState.unwrappedGiftMessageIds.contains(messageUniqueId)
    }

    public func willShakeGift(_ messageUniqueId: String) -> Bool {
        let (justInserted, _) = self.viewState.shakenGiftMessageIds.insert(messageUniqueId)
        return justInserted
    }

    public func willUnwrapGift(_ itemViewModel: CVItemViewModelImpl) {
        self.viewState.unwrappedGiftMessageIds.insert(itemViewModel.interaction.uniqueId)
        self.markGiftAsOpened(itemViewModel.interaction)
    }

    private func markGiftAsOpened(_ interaction: TSInteraction) {
        guard let outgoingMessage = interaction as? TSOutgoingMessage else {
            return
        }
        guard outgoingMessage.giftBadge?.redemptionState == .pending else {
            return
        }
        self.databaseStorage.asyncWrite { transaction in
            outgoingMessage.anyUpdateOutgoingMessage(transaction: transaction) {
                $0.giftBadge?.redemptionState = .opened
            }

            self.receiptManager.outgoingGiftWasOpened(outgoingMessage, transaction: transaction)
        }
    }

    public func didTapGiftBadge(_ itemViewModel: CVItemViewModelImpl, profileBadge: ProfileBadge, isExpired: Bool, isRedeemed: Bool) {
        AssertIsOnMainThread()

        let viewControllerToPresent: UIViewController

        switch itemViewModel.interaction {
        case let incomingMessage as TSIncomingMessage:
            viewControllerToPresent = self.incomingGiftSheet(
                incomingMessage: incomingMessage,
                profileBadge: profileBadge,
                isExpired: isExpired,
                isRedeemed: isRedeemed
            )

        case is TSOutgoingMessage:
            guard let thread = thread as? TSContactThread else {
                owsFailDebug("Clicked a gift badge that wasn't in a contact thread")
                return
            }

            viewControllerToPresent = BadgeGiftingThanksSheet(thread: thread, badge: profileBadge)

        default:
            owsFailDebug("Tapped on gift that's not a message")
            return
        }

        self.present(viewControllerToPresent, animated: true)
    }

    private func incomingGiftSheet(
        incomingMessage: TSIncomingMessage,
        profileBadge: ProfileBadge,
        isExpired: Bool,
        isRedeemed: Bool
    ) -> UIViewController {
        if isExpired {
            let mode: BadgeIssueSheetState.Mode
            if isRedeemed {
                let hasCurrentSubscription = self.databaseStorage.read { transaction -> Bool in
                    self.subscriptionManager.hasCurrentSubscription(transaction: transaction)
                }
                mode = .giftBadgeExpired(hasCurrentSubscription: hasCurrentSubscription)
            } else {
                let fullName = self.databaseStorage.read { transaction -> String in
                    let authorAddress = incomingMessage.authorAddress
                    return self.contactsManager.displayName(for: authorAddress, tx: transaction).resolvedValue()
                }
                mode = .giftNotRedeemed(fullName: fullName)
            }
            let sheet = BadgeIssueSheet(badge: profileBadge, mode: mode)
            sheet.delegate = self
            return sheet
        }
        if isRedeemed {
            let shortName = self.databaseStorage.read { transaction -> String in
                let authorAddress = incomingMessage.authorAddress
                return self.contactsManager.displayName(for: authorAddress, tx: transaction).resolvedValue(useShortNameIfAvailable: true)
            }
            return BadgeGiftingAlreadyRedeemedSheet(badge: profileBadge, shortName: shortName)
        }
        return self.giftRedemptionSheet(incomingMessage: incomingMessage, profileBadge: profileBadge)
    }

    private func giftRedemptionSheet(incomingMessage: TSIncomingMessage, profileBadge: ProfileBadge) -> UIViewController {
        let authorAddress = incomingMessage.authorAddress
        let shortName = self.databaseStorage.read { transaction in
            self.contactsManager.displayName(for: authorAddress, tx: transaction).resolvedValue(useShortNameIfAvailable: true)
        }
        return BadgeThanksSheet(
            newBadge: profileBadge,
            thanksType: .giftReceived(
                shortName: shortName,
                notNowAction: { [weak self] in self?.showRedeemBadgeLaterText() },
                incomingMessage: incomingMessage
            ),
            oldBadgesSnapshot: .current()
        )
    }

    private func showRedeemBadgeLaterText() {
        let text = OWSLocalizedString(
            "DONATION_ON_BEHALF_OF_A_FRIEND_REDEEM_BADGE_LATER",
            comment: "When you receive a badge as a result of a donation from a friend, a screen is shown. This toast is shown when dismissing that screen if you do not redeem the badge."
        )
        self.presentToastCVC(text)
    }

}

extension ConversationViewController: BadgeIssueSheetDelegate {
    func badgeIssueSheetActionTapped(_ action: BadgeIssueSheetAction) {
        switch action {
        case .dismiss:
            break
        case .openDonationView:
            let appSettings = AppSettingsViewController.inModalNavigationController()
            let donateViewController = DonateViewController(preferredDonateMode: .oneTime) { [weak self] finishResult in
                switch finishResult {
                case let .completedDonation(donateSheet, receiptCredentialSuccessMode):
                    donateSheet.dismiss(animated: true) { [weak self] in
                        guard
                            let self,
                            let badgeThanksSheetPresenter = BadgeThanksSheetPresenter.loadWithSneakyTransaction(
                                successMode: receiptCredentialSuccessMode
                            )
                        else { return }

                        badgeThanksSheetPresenter.presentBadgeThanksAndClearSuccess(
                            fromViewController: self
                        )
                    }
                case let .monthlySubscriptionCancelled(donateSheet, toastText):
                    donateSheet.dismiss(animated: true) { [weak self] in
                        guard let self = self else { return }
                        self.view.presentToast(text: toastText, fromViewController: self)
                    }
                }
            }
            appSettings.viewControllers += [
                DonationSettingsViewController(),
                donateViewController
            ]
            self.presentFormSheet(appSettings, animated: true, completion: nil)
        }
    }
}
