import * as net from "net";

export enum Severity {
    OK = "OK",
    Warning = "WARN",
    Error = "ERR",
    Skip = "SKIP",
}

export interface Status {
    severity: Severity;
    message: string;
}

export interface DiagnosticStep {
    run: () => Promise<Status>;
    name: string;
    status?: Status;
}

export interface Diagnostic {
    title: string;
    steps: Array<DiagnosticStep>;
    status?: Status;
}

const domain = "/web/access/smgames.club";

export var diagnostics: Ref<Diagnostic[]> = ref([
    {
        title: "Matrix Server Acs.",
        steps: [
            {
                name: "Version access",
                run: () => {
                    // The Matrix server should be hosted at smgames.club - Attempt to connect to the server
                    // TODO: Better checking - This just checks for resources.

                    // Check _matrix/client/versions - Should return a JSON object
                    // Else, return an error
                    const url = `${domain}/_matrix/client/versions`;
                    return fetch(url)
                        .then((response) => {
                            if (response.ok) {
                                return {
                                    severity: Severity.OK,
                                    message: "Matrix server is accessible.",
                                };
                            } else {
                                return {
                                    severity: Severity.Error,
                                    message: "Response was not OK.",
                                };
                            }
                        })
                        .catch((error) => {
                            return {
                                severity: Severity.Error,
                                message:
                                    "Unable to get a response when querying the version: " +
                                    error,
                            };
                        });
                },
            },
        ],
    },
    {
        title: "Primary Domain",
        steps: [
            {
                name: "Fetch Index",
                run: () => {
                    // Check that the domain resolves
                    const url = `${domain}`;
                    return fetch(url)
                        .then((response) => {
                            if (response.ok) {
                                return {
                                    severity: Severity.OK,
                                    message: "Able to fetch.",
                                };
                            } else {
                                return {
                                    severity: Severity.Error,
                                    message: "Response was not OK.",
                                };
                            }
                        })
                        .catch((error) => {
                            return {
                                severity: Severity.Error,
                                message:
                                    "Unable to get a response when querying the domain: " +
                                    error,
                            };
                        });
                },
            },
        ],
    },
    {
        title: "Services Reverse Proxy",
        steps: [
            {
                name: "Access Index",
                run: () => {
                    const service_url = "/web/access/services.smgames.club";
                    return fetch(service_url)
                        .then((response) => {
                            if (response.ok) {
                                return {
                                    severity: Severity.OK,
                                    message: "Able to fetch index.",
                                };
                            } else {
                                return {
                                    severity: Severity.Error,
                                    message: "Index response was not OK: " +
                                        response.statusText,
                                };
                            }
                        })
                        .catch((error) => {
                            return {
                                severity: Severity.Error,
                                message:
                                    "Unable to get a response when querying the domain index: " +
                                    error,
                            };
                        });
                },
            },
        ],
    },
    {
        title: "Minecraft",
        steps: [
            {
                name: "WS Connect",
                run: () => {
                    const minecraft_server = "ws://social.smgames.club:25565"; // WebSocket URL for Minecraft
                    const timeoutDuration = 100; // Timeout duration in ms

                    return new Promise<Status>((resolve, reject) => {
                        const socket = new WebSocket(minecraft_server);

                        // Set up a timeout to reject the promise if the connection takes too long
                        const timeout = setTimeout(() => {
                            reject({
                                severity: Severity.Error,
                                message:
                                    `Timeout while trying to connect to Minecraft server via WebSocket on port 25565.`,
                            });
                            socket.close(); // Close the WebSocket connection in case of timeout
                        }, timeoutDuration);

                        socket.onopen = () => {
                            clearTimeout(timeout); // Clear the timeout once the connection is successful
                            resolve({
                                severity: Severity.OK,
                                message:
                                    "WebSocket connection successful to Minecraft server on port 25565.",
                            });
                            socket.close(); // Close the WebSocket connection after success
                        };

                        socket.onerror = (err) => {
                            clearTimeout(timeout); // Clear the timeout if an error occurs
                            reject({
                                severity: Severity.Error,
                                message:
                                    "Unable to connect to Minecraft server via WebSocket on port 25565: " +
                                    err,
                            });
                            socket.close(); // Close the WebSocket connection after error
                        };

                        socket.onclose = (event) => {
                            clearTimeout(timeout); // Clear the timeout when the connection is closed
                            if (!event.wasClean) {
                                reject({
                                    severity: Severity.Error,
                                    message:
                                        "WebSocket connection closed unexpectedly to Minecraft server on port 25565.",
                                });
                            }
                        };

                        socket.onmessage = (event) => {
                            // Optionally handle any WebSocket messages if necessary
                        };
                    });
                },
            },
        ],
    },
    {
        title: "Forgejo",
        steps: [
            {
                name: "Fetch Index",
                run: () => {
                    const service_url = "/web/access/git.smgames.club";
                    return fetch(service_url)
                        .then((response) => {
                            if (response.ok) {
                                return {
                                    severity: Severity.OK,
                                    message: "Able to fetch index.",
                                };
                            } else {
                                return {
                                    severity: Severity.Error,
                                    message: "Index response was not OK: " +
                                        response.statusText,
                                };
                            }
                        })
                        .catch((error) => {
                            return {
                                severity: Severity.Error,
                                message:
                                    "Unable to get a response when querying the domain index: " +
                                    error,
                            };
                        });
                },
            },
        ],
    },
    {
        title: "Social",
        steps: [
            {
                name: "Fetch Index",
                run: () => {
                    const service_url = "/web/access/social.smgames.club";
                    return fetch(service_url)
                        .then((response) => {
                            if (response.ok) {
                                return {
                                    severity: Severity.OK,
                                    message: "Able to fetch index.",
                                };
                            } else {
                                return {
                                    severity: Severity.Error,
                                    message: "Index response was not OK: " +
                                        response.statusText,
                                };
                            }
                        })
                        .catch((error) => {
                            return {
                                severity: Severity.Error,
                                message:
                                    "Unable to get a response when querying the domain index: " +
                                    error,
                            };
                        });
                },
            },
        ]
    }
]);

// Run all diagnostics
export async function run_diagnostics() {
    for (const diagnostic of diagnostics.value) {
        try {
            if (diagnostic.steps === undefined || diagnostic.steps.length === 0) {
                diagnostic.status = {
                    severity: Severity.Skip,
                    message: "No steps available to take.",
                };
                continue;
            }
            diagnostic.status = {
                severity: Severity.OK,
                message: "Successfully verified.",
            };
            for (const step of diagnostic.steps) {
                try {
                    const res = await step.run();
                    step.status = res;
                } catch (err: any) {
                    step.status = {
                        severity: Severity.Error,
                        message: err.message,
                    };
                }
                if (step.status.severity === Severity.Error) {
                    diagnostic.status = {
                        severity: Severity.Error,
                        message: "One or more steps failed.",
                    };
                }
            }
        } catch (err: any) {
            diagnostic.status = {
                severity: Severity.Error,
                message: err.message,
            };
        }
    }
}

// Run diagnostics on load
run_diagnostics();