import Defaults
import Foundation
import SwiftyJSON

final class ImportSettingsFileModel: ObservableObject {
    static let shared = ImportSettingsFileModel()

    var locationsSettingsGroupImporter: LocationsSettingsGroupImporter? {
        if let locationsSettings = json.dictionaryValue["locationsSettings"] {
            return LocationsSettingsGroupImporter(
                json: locationsSettings,
                includePublicLocations: importExportModel.isGroupEnabled(.locationsSettings),
                includedInstancesIDs: sheetViewModel.selectedInstances,
                includedAccountsIDs: sheetViewModel.selectedAccounts,
                includedAccountsPasswords: sheetViewModel.importableAccountsPasswords
            )
        }
        return nil
    }

    var importExportModel = ImportExportSettingsModel.shared
    var sheetViewModel = ImportSettingsSheetViewModel.shared

    var loadTask: URLSessionTask?

    func isGroupIncludedInFile(_ group: ImportExportSettingsModel.ExportGroup) -> Bool {
        switch group {
        case .locationsSettings:
            return isPublicInstancesSettingsGroupInFile || instancesOrAccountsInFile
        default:
            return !groupJSON(group).isEmpty
        }
    }

    var isPublicInstancesSettingsGroupInFile: Bool {
        guard let dict = groupJSON(.locationsSettings).dictionary else { return false }

        return dict.keys.contains("instancesManifest") || dict.keys.contains("countryOfPublicInstances")
    }

    var instancesOrAccountsInFile: Bool {
        guard let dict = groupJSON(.locationsSettings).dictionary else { return false }

        return (dict.keys.contains("instances") && !(dict["instances"]?.arrayValue.isEmpty ?? true)) ||
            (dict.keys.contains("accounts") && !(dict["accounts"]?.arrayValue.isEmpty ?? true))
    }

    func groupJSON(_ group: ImportExportSettingsModel.ExportGroup) -> JSON {
        json.dictionaryValue[group.rawValue] ?? .init()
    }

    func performImport() {
        if importExportModel.isGroupSelected(.browsingSettings), isGroupIncludedInFile(.browsingSettings) {
            BrowsingSettingsGroupImporter(json: groupJSON(.browsingSettings)).performImport()
        }

        if importExportModel.isGroupSelected(.playerSettings), isGroupIncludedInFile(.playerSettings) {
            PlayerSettingsGroupImporter(json: groupJSON(.playerSettings)).performImport()
        }

        if importExportModel.isGroupSelected(.controlsSettings), isGroupIncludedInFile(.controlsSettings) {
            ConstrolsSettingsGroupImporter(json: groupJSON(.controlsSettings)).performImport()
        }

        if importExportModel.isGroupSelected(.qualitySettings), isGroupIncludedInFile(.qualitySettings) {
            QualitySettingsGroupImporter(json: groupJSON(.qualitySettings)).performImport()
        }

        if importExportModel.isGroupSelected(.historySettings), isGroupIncludedInFile(.historySettings) {
            HistorySettingsGroupImporter(json: groupJSON(.historySettings)).performImport()
        }

        if importExportModel.isGroupSelected(.sponsorBlockSettings), isGroupIncludedInFile(.sponsorBlockSettings) {
            SponsorBlockSettingsGroupImporter(json: groupJSON(.sponsorBlockSettings)).performImport()
        }

        locationsSettingsGroupImporter?.performImport()

        if importExportModel.isGroupSelected(.advancedSettings), isGroupIncludedInFile(.advancedSettings) {
            AdvancedSettingsGroupImporter(json: groupJSON(.advancedSettings)).performImport()
        }

        if importExportModel.isGroupSelected(.recentlyOpened), isGroupIncludedInFile(.recentlyOpened) {
            RecentlyOpenedImporter(json: groupJSON(.recentlyOpened)).performImport()
        }

        if importExportModel.isGroupSelected(.otherData), isGroupIncludedInFile(.otherData) {
            OtherDataSettingsGroupImporter(json: groupJSON(.otherData)).performImport()
        }
    }

    @Published var json = JSON()

    func loadData(_ url: URL) {
        json = JSON()
        loadTask?.cancel()

        loadTask = URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
            guard let data else { return }

            if let json = try? JSON(data: data) {
                DispatchQueue.main.async { [weak self] in
                    guard let self else { return }
                    self.json = json

                    self.sheetViewModel.reset(locationsSettingsGroupImporter)
                    self.importExportModel.reset(self)
                }
            }
        }
        loadTask?.resume()
    }

    func filename(_ url: URL) -> String {
        String(url.lastPathComponent.dropLast(ImportExportSettingsModel.settingsExtension.count + 1))
    }

    var metadataBuild: String? {
        if let build = json.dictionaryValue["metadata"]?.dictionaryValue["build"]?.string {
            return build
        }

        return nil
    }

    var metadataPlatform: String? {
        if let platform = json.dictionaryValue["metadata"]?.dictionaryValue["platform"]?.string {
            return platform
        }

        return nil
    }

    var metadataDate: String? {
        if let timestamp = json.dictionaryValue["metadata"]?.dictionaryValue["timestamp"]?.doubleValue {
            let date = Date(timeIntervalSince1970: timestamp)
            return dateFormatter.string(from: date)
        }

        return nil
    }

    var dateFormatter: DateFormatter {
        let formatter = DateFormatter()
        formatter.dateStyle = .long
        formatter.timeStyle = .medium

        return formatter
    }
}