import AppIntents
import Foundation
import Library

struct StartServiceIntent: AppIntent {
    static var title: LocalizedStringResource = "Start sing-box"

    static var description =
        IntentDescription("Start or reload sing-box service with specified profile")

    static var parameterSummary: some ParameterSummary {
        Summary("Start sing-box service with profile \(\.$profile).")
    }

    @Parameter(title: "Profile", optionsProvider: ProfileProvider())
    var profile: String

    func perform() async throws -> some IntentResult & ProvidesDialog {
        guard let extensionProfile = try await (ExtensionProfile.load()) else {
            throw NSError(domain: "IntentsExtension", code: 0, userInfo: [NSLocalizedDescriptionKey: String(localized: "NetworkExtension not installed")])
        }
        let profileList = try await ProfileManager.list()
        let specifiedProfile = profileList.first { $0.name == profile }
        var profileChanged = false
        if let specifiedProfile {
            let specifiedProfileID = specifiedProfile.mustID
            if await SharedPreferences.selectedProfileID.get() != specifiedProfileID {
                await SharedPreferences.selectedProfileID.set(specifiedProfileID)
                profileChanged = true
            }
        } else if profile != "default" {
            throw NSError(domain: "IntentsExtension", code: 0, userInfo: [NSLocalizedDescriptionKey: String(localized: "Specified profile not found: \(profile)")])
        }
        if await extensionProfile.status == .connected {
            if !profileChanged {
                return .result(dialog: "Service is already running")
            }
            try await extensionProfile.reloadService()
        } else if await extensionProfile.status.isConnected {
            try await extensionProfile.restart()
        } else {
            try await extensionProfile.start()
        }
        return .result(dialog: "Service started")
    }
}

struct RestartServiceIntent: AppIntent {
    static var title: LocalizedStringResource = "Restart sing-box"

    static var description =
        IntentDescription("Restart sing-box service")

    static var parameterSummary: some ParameterSummary {
        Summary("Restart sing-box service")
    }

    func perform() async throws -> some IntentResult & ProvidesDialog {
        guard let extensionProfile = try await (ExtensionProfile.load()) else {
            return .result(dialog: "Service is not installed")
        }
        if await extensionProfile.status == .connected {
            try await extensionProfile.reloadService()
        } else if await extensionProfile.status.isConnected {
            try await extensionProfile.restart()
        } else {
            try await extensionProfile.start()
        }
        return .result(dialog: "Service restarted")
    }
}

struct StopServiceIntent: AppIntent {
    static var title: LocalizedStringResource = "Stop sing-box"

    static var description =
        IntentDescription("Stop sing-box service")

    static var parameterSummary: some ParameterSummary {
        Summary("Stop sing-box service")
    }

    func perform() async throws -> some IntentResult & ProvidesDialog {
        guard let extensionProfile = try await (ExtensionProfile.load()) else {
            return .result(dialog: "Service is not installed")
        }
        try await extensionProfile.stop()
        return .result(dialog: "Service stopped")
    }
}

struct ToggleServiceIntent: AppIntent {
    static var title: LocalizedStringResource = "Toggle sing-box"

    static var description =
        IntentDescription("Toggle sing-box service")

    static var parameterSummary: some ParameterSummary {
        Summary("Toggle sing-box service")
    }

    func perform() async throws -> some IntentResult & ReturnsValue<Bool> {
        guard let extensionProfile = try await (ExtensionProfile.load()) else {
            return .result(value: false)
        }
        if await extensionProfile.status.isConnected {
            try await extensionProfile.stop()
            return .result(value: false)

        } else {
            try await extensionProfile.start()
            return .result(value: true)
        }
    }
}

struct GetServiceStatus: AppIntent {
    static var title: LocalizedStringResource = "Get is sing-box service started"

    static var description =
        IntentDescription("Get is sing-box service started")

    static var parameterSummary: some ParameterSummary {
        Summary("Get is sing-box service started")
    }

    func perform() async throws -> some IntentResult & ReturnsValue<Bool> {
        guard let extensionProfile = try await (ExtensionProfile.load()) else {
            return .result(value: false)
        }
        return await .result(value: extensionProfile.status.isConnected)
    }
}

struct GetCurrentProfile: AppIntent {
    static var title: LocalizedStringResource = "Get current sing-box profile"

    static var description =
        IntentDescription("Get current sing-box profile")

    static var parameterSummary: some ParameterSummary {
        Summary("Get current sing-box profile")
    }

    func perform() async throws -> some IntentResult & ReturnsValue<String> {
        guard let profile = try await ProfileManager.get(SharedPreferences.selectedProfileID.get()) else {
            throw NSError(domain: "IntentsExtension", code: 0, userInfo: [NSLocalizedDescriptionKey: String(localized: "No profile selected")])
        }
        return .result(value: profile.name)
    }
}

struct UpdateProfileIntent: AppIntent {
    static var title: LocalizedStringResource = "Update sing-box profile"

    static var description =
        IntentDescription("Update specified sing-box profile")

    static var parameterSummary: some ParameterSummary {
        Summary("Update sing-box profile \(\.$profile).")
    }

    @Parameter(title: "Profile", optionsProvider: RemoteProfileProvider())
    var profile: String

    init() {}
    func perform() async throws -> some IntentResult & ProvidesDialog {
        guard let profile = try await ProfileManager.get(by: profile) else {
            throw NSError(domain: "IntentsExtension", code: 0, userInfo: [NSLocalizedDescriptionKey: String(localized: "Specified profile not found: \(profile)")])
        }
        if profile.type != .remote {
            throw NSError(domain: "IntentsExtension", code: 0, userInfo: [NSLocalizedDescriptionKey: String(localized: "Specified profile is not a remote profile")])
        }
        try await profile.updateRemoteProfile()
        return .result(dialog: "Profile updated")
    }
}

class ProfileProvider: DynamicOptionsProvider {
    func results() async throws -> [String] {
        var profileNames = try await ProfileManager.list().map(\.name)
        if !profileNames.contains("default") {
            profileNames.insert("default", at: 0)
        }
        return profileNames
    }
}

class RemoteProfileProvider: DynamicOptionsProvider {
    func results() async throws -> [String] {
        try await ProfileManager.listRemote().map(\.name)
    }
}

struct ServiceShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: StartServiceIntent(),
            phrases: ["Start \(.applicationName)"],
            shortTitle: "Start",
            systemImageName: "power"
        )
        AppShortcut(
            intent: StopServiceIntent(),
            phrases: ["Stop \(.applicationName)"],
            shortTitle: "Stop",
            systemImageName: "stop.fill"
        )
        AppShortcut(
            intent: RestartServiceIntent(),
            phrases: ["Restart \(.applicationName)"],
            shortTitle: "Restart",
            systemImageName: "arrow.clockwise"
        )
        AppShortcut(
            intent: ToggleServiceIntent(),
            phrases: ["Toggle \(.applicationName)"],
            shortTitle: "Toggle",
            systemImageName: "arrow.triangle.2.circlepath"
        )
        AppShortcut(
            intent: UpdateProfileIntent(),
            phrases: ["Update \(.applicationName) profile"],
            shortTitle: "Update Profile",
            systemImageName: "arrow.down.circle"
        )
    }
}
