import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
import DiscordKit
import XMLCoder

struct Wolfram {
    static let token = ProcessInfo.processInfo.environment["WOLFRAM_APP_ID"]!
    static let apiUrl = "http://api.wolframalpha.com/v2/query"

    static func getWolfram(_ question: String) async throws -> (String, URL?) {
        let encQuestion = question.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
        let url = URL(string: "\(apiUrl)?appid=\(token)&input=\(encQuestion!)")!
        let (data, _) = try await URLSession.shared.data(from: url)

        let wolframRes = try XMLDecoder().decode(WolframQueryResult.self, from: data)

        let resultPod = wolframRes.pod.first(where: { $0.primary ?? false || $0.id == "Result" })

        var ans: String?
        var img: URL?

        if let resultPod = resultPod {
            ans = String(resultPod.subpod.compactMap(\.plaintext).joined(separator: "\n"))
                .replacingOccurrences(of: " | ", with: ": ")
        }
        if let imgPod = wolframRes.pod.first(where: {
            ["RootPlot", "NumberLine", "Plot", "ImplicitPlot", "3DPlot"].contains($0.id) ||
            ($0.id == "Example" && $0.scanner == "Dice")
        }) {
            ans = ans ?? "Plot:"
            img = imgPod.subpod.first?.img.src
        }

        if ans == nil,
        let maybePod = wolframRes.pod.first(where: { $0.title == "Input interpretation" }),
        let maybeText = maybePod.subpod.first?.plaintext
            .replacingOccurrences(of: " | ", with: ": ") {
            ans = "<:smol_rise:852763040452575252> I don't know. Maybe you meant '\(maybeText)'"
        }

        return (ans ?? "<:smol_rise:852763040452575252> sorry, I have no idea (´._.`)", img)
    }

    static func handleMath(
        _ args: ArraySlice<String.SubSequence>,
        client: ApiClient,
        ctx: MessageCreate
    ) async throws {
        let typingIndicatorTask = Task {
            while !Task.isCancelled {
                try await client.triggerTypingIndicator(channelId: ctx.channel_id)
                try await Task.sleep(for: .seconds(8))
            }
        }

        let question = String(args.joined(separator: " "))

        let (answer, img) = try await getWolfram(question)

        var attachments: [Embed] = []

        if let img = img {
            attachments.append(.init(image: .init(url: img.absoluteString)))
        }
        typingIndicatorTask.cancel()

        try await client.createMessage(channelId: ctx.channel_id, payload: .init(
            content: answer,
            message_reference: .init(
                type: 0,
                message_id: ctx.id,
                channel_id: ctx.channel_id,
                guild_id: ctx.guild_id,
            ),
            embeds: attachments
        ))
    }
}

struct WolframQueryResult: Codable {
    struct Pod: Codable {
        let title: String
        let id: String
        let scanner: String
        let primary: Bool?

        let subpod: [Subpod]
    }

    struct Subpod: Codable {
        let title: String
        let img: Image
        let plaintext: String
    }

    struct Image: Codable {
        let src: URL
    }

    let success: Bool
    let numpods: Int

    let pod: [Pod]
}

