//
//  See LICENSE folder for this template’s licensing information.
//
//  Abstract:
//  Web Polling 受信

import Foundation

public protocol HTTPPollingDelegate: AnyObject {
    func didWebReceiveMessage(messageText: String, codeText: String)
    func didWebFailWithError(_ error: Error)
}

public class HTTPPolling {
    private let url: URL
    private var timer: Timer?
    private var lastTimestamp: Int = 0
    public weak var delegate: HTTPPollingDelegate?
    private let schoolId: String
    private let pollingInterval: TimeInterval

    public init(url: URL, schoolId: String, pollingInterval: TimeInterval = 3.0) {
        self.url = url
        self.schoolId = schoolId
        self.pollingInterval = pollingInterval
    }

    public func startPolling() {
        stopPolling() // タイマーがすでに存在する場合は停止
        timer = Timer.scheduledTimer(withTimeInterval: pollingInterval, repeats: true) { [weak self] _ in
            self?.fetchMessages()
        }
    }

    public func stopPolling() {
        timer?.invalidate()
        timer = nil
    }

    private func fetchMessages() {
        guard let url = URL(string: "\(url.absoluteString)?lastTimestamp=\(lastTimestamp)&schoolId=\(schoolId)") else { return }
        let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
            if let error = error {
                self?.handleError(error)
                return
            }

            guard let data = data else {
                let error = NSError(domain: "HTTPPollingError", code: 0, userInfo: [NSLocalizedDescriptionKey: "No data received"])
                self?.handleError(error)
                return
            }

            self?.parseMessage(data: data)
        }
        task.resume()
    }

    private func handleError(_ error: Error) {
        delegate?.didWebFailWithError(error)
        // エラーが発生した場合には、タイマーを停止するか、再試行のロジックを追加できます
        stopPolling() // 必要に応じてタイマーを停止する
    }

    private func parseMessage(data: Data) {
        do {
            if let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
                for messageDict in jsonArray {
                    if let timestamp = messageDict["timestamp"] as? Int,
                       let message = messageDict["message"] as? String,
                       let codetext = messageDict["codetext"] as? String {
                       
                        // メッセージがネストされたJSONとして受け取られる場合、その文字列を再度辞書型として解析する
                        let processedMessage: String
                        let processedCodetext: String
                        
                        if let nestedData = message.data(using: .utf8),
                           let nestedMessage = try? JSONSerialization.jsonObject(with: nestedData, options: []) as? [String: Any],
                           let actualMessage = nestedMessage["message"] as? String {
                            processedMessage = actualMessage
                        } else {
                            processedMessage = message
                        }
                        
                        if let nestedDataCodetext = codetext.data(using: .utf8),
                           let nestedCodetext = try? JSONSerialization.jsonObject(with: nestedDataCodetext, options: []) as? [String: Any],
                           let actualCodetext = nestedCodetext["codetext"] as? String {
                            processedCodetext = actualCodetext
                        } else {
                            processedCodetext = codetext
                        }
                        
                        // `processedMessage` と `processedCodetext` を delegate に渡す
                        delegate?.didWebReceiveMessage(messageText: processedMessage, codeText: processedCodetext)
                        
                        lastTimestamp = max(lastTimestamp, timestamp)
                    } else {
                        print("Failed to parse message or codetext")
                    }
                }
            } else {
                let error = NSError(domain: "HTTPPollingError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid JSON format"])
                handleError(error)
            }
        } catch {
            handleError(error)
        }
    }
}
