import Foundation

final class RemotePush: ObservableObject {

    @Published
    var isTransmittingToRemote = false

    @Published
    var lastPushWasSuccessful = true

    func transmitToRemote(settings: GeneralSettings, outputFolder: String, outputHandler: @escaping (String) -> Void) {
        guard !isTransmittingToRemote else { return }
        DispatchQueue.main.async {
            self.isTransmittingToRemote = true
        }
        DispatchQueue.global().async {
            let success = self.transmit(
                outputFolder: outputFolder,
                remoteUser: settings.remoteUserForUpload,
                remotePort: settings.remotePortForUpload,
                remoteDomain: settings.url,
                remotePath: settings.remotePathForUpload,
                excludedItems: [".git"],
                outputHandler: outputHandler)
            DispatchQueue.main.async {
                self.isTransmittingToRemote = false
                self.lastPushWasSuccessful = success
            }
        }
    }

    private func transmit(
        outputFolder: String,
        remoteUser: String,
        remotePort: Int,
        remoteDomain: String,
        remotePath: String,
        excludedItems: [String],
        outputHandler: @escaping (String) -> Void
    ) -> Bool {
        let remoteDomain = remoteDomain.withHttpPrefixRemoved
        let remotePath = remotePath.withLeadingSlash.withTrailingSlash
        let outputFolder = outputFolder.withLeadingSlash.withTrailingSlash

        let process = Process()
        process.executableURL = URL(fileURLWithPath: "/bin/bash")
        let arguments = [
            "/opt/homebrew/bin/rsync",
            "-hrutv",
            "--info=progress2"]
        + excludedItems.reduce(into: []) { $0 += ["--exclude", $1] }
        + [
            "-e", "\"/opt/homebrew/bin/ssh -p \(remotePort)\"",
            outputFolder,
            "\(remoteUser)@\(remoteDomain):\(remotePath)"
        ]

        let argument = arguments.joined(separator: " ")

        process.arguments = ["-c", argument]

        let pipe = Pipe()
        process.standardOutput = pipe
        process.standardError = pipe

        let fileHandle = pipe.fileHandleForReading

        // Use a DispatchQueue to read output asynchronously
        fileHandle.readabilityHandler = { fileHandle in
            if let output = String(data: fileHandle.availableData, encoding: .utf8), !output.isEmpty {
                outputHandler(output)
            }
        }

        process.launch()
        process.waitUntilExit()

        if process.terminationStatus == 0 {
            return true
        }
        return false
    }
}
