//
//  UnifiedFeedbackFormViewController.swift
//
//  Copyright © 2023 DuckDuckGo. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//

import Foundation
import AppKit
import SwiftUI
import Combine
import PixelKit
import Subscription
import Networking

final class UnifiedFeedbackFormViewController: NSViewController {
    // Using a dynamic height in the form was causing layout problems and couldn't be completed in time for the release that needed this form.
    // As a temporary measure, the heights of each form state are hardcoded.
    // This should be cleaned up later, and eventually use the `sizingOptions` property of NSHostingController.
    enum Constants {
        static let landingPageHeight = 260.0
        static let feedbackFormMiniHeight = 350.0
        static let feedbackFormCompactHeight = 430.0
        static let feedbackFormHeight = 740.0
        static let feedbackSentHeight = 350.0
    }

    private let defaultSize = CGSize(width: 480, height: Constants.landingPageHeight)

    private let feedbackSender: UnifiedFeedbackSender
    private let viewModel: UnifiedFeedbackFormViewModel

    private var heightConstraint: NSLayoutConstraint?
    private var cancellables = Set<AnyCancellable>()

    init(feedbackSender: UnifiedFeedbackSender = DefaultFeedbackSender(),
         source: UnifiedFeedbackSource = .default) {
        self.feedbackSender = feedbackSender
        self.viewModel = UnifiedFeedbackFormViewModel(subscriptionManager: Application.appDelegate.subscriptionManager,
                                                      apiService: DefaultAPIService(),
                                                      vpnMetadataCollector: DefaultVPNMetadataCollector(accountManager: Application.appDelegate.subscriptionManager.accountManager),
                                                      feedbackSender: feedbackSender,
                                                      source: source)

        super.init(nibName: nil, bundle: nil)
        self.viewModel.delegate = self
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func loadView() {
        view = NSView(frame: NSRect(origin: CGPoint.zero, size: defaultSize))
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let feedbackFormView = UnifiedFeedbackFormView()
        let hostingView = NSHostingView(rootView: feedbackFormView.environmentObject(self.viewModel))
        hostingView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(hostingView)

        let heightConstraint = hostingView.heightAnchor.constraint(equalToConstant: defaultSize.height)
        self.heightConstraint = heightConstraint

        NSLayoutConstraint.activate([
            heightConstraint,
            hostingView.widthAnchor.constraint(equalToConstant: defaultSize.width),
            hostingView.topAnchor.constraint(equalTo: view.topAnchor),
            hostingView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            hostingView.leftAnchor.constraint(equalTo: view.leftAnchor),
            hostingView.rightAnchor.constraint(equalTo: view.rightAnchor)
        ])

        subscribeToViewModelChanges()
    }

    func subscribeToViewModelChanges() {
        viewModel.$viewState
            .receive(on: DispatchQueue.main)
            .sink { [weak self] _ in
                self?.updateViewHeight()
            }
            .store(in: &cancellables)

        Publishers.MergeMany(
            viewModel.$selectedReportType,
            viewModel.$selectedCategory,
            viewModel.$selectedSubcategory
        )
        .receive(on: DispatchQueue.main)
        .sink { [weak self] _ in
            self?.updateViewHeight()
        }
        .store(in: &cancellables)
    }

    private func updateViewHeight() {
        switch viewModel.viewState {
        case .feedbackPending:
            if UnifiedFeedbackReportType(rawValue: viewModel.selectedReportType) == .prompt {
                heightConstraint?.constant = Constants.landingPageHeight
            } else if UnifiedFeedbackReportType(rawValue: viewModel.selectedReportType) == .reportIssue,
                      UnifiedFeedbackCategory(rawValue: viewModel.selectedCategory) == .prompt ||
                      viewModel.selectedSubcategory == PrivacyProFeedbackSubcategory.prompt.rawValue {
                heightConstraint?.constant = Constants.feedbackFormMiniHeight
            } else {
                heightConstraint?.constant = viewModel.usesCompactForm ? Constants.feedbackFormCompactHeight : Constants.feedbackFormHeight
            }
        case .feedbackSending:
            heightConstraint?.constant = viewModel.usesCompactForm ? Constants.feedbackFormCompactHeight : Constants.feedbackFormHeight
        case .feedbackSent:
            heightConstraint?.constant = Constants.feedbackSentHeight
        case .feedbackSendingFailed:
            heightConstraint?.constant = (viewModel.usesCompactForm ? Constants.feedbackFormCompactHeight : Constants.feedbackFormHeight) + 20.0
        }
    }

}

extension UnifiedFeedbackFormViewController: UnifiedFeedbackFormViewModelDelegate {

    func feedbackViewModelDismissedView(_ viewModel: UnifiedFeedbackFormViewModel) {
        dismiss()
    }

}