import type {Logger} from "@foxxmd/logging";
import { HTTPError } from "got";
import { gotify } from 'gotify';
import request from 'superagent';
import type {GotifyConfig, PrioritiesConfig, WebhookPayload} from "../common/infrastructure/config/health/webhooks.ts";
import { AbstractWebhookNotifier } from "./AbstractWebhookNotifier.ts";
import { isPortReachable, normalizeWebAddress } from "../utils/NetworkUtils.ts";
import type {URLData} from "../../core/Atomic.ts";

export class GotifyWebhookNotifier extends AbstractWebhookNotifier {

    declare config: GotifyConfig;

    priorities: PrioritiesConfig;

    protected endpoint: URLData;

    constructor(defaultName: string, config: GotifyConfig, logger: Logger) {
        super('Gotify', defaultName, config, logger);
        this.requiresAuth = true;
        const {
            info = 5,
            warn = 7,
            error = 10
        } = this.config.priorities || {};

        this.priorities = {
            info,
            warn,
            error
        }

    }

    initialize = async () => {
        // check url is correct as a courtesy
        this.endpoint = normalizeWebAddress(this.config.url);
        this.logger.verbose(`Config URL: '${this.config.url}' => Normalized: '${this.endpoint.normal}'`)

        this.initialized = true; // always set as ready to go. Server issues may be transient.

        try {
            await isPortReachable(this.endpoint.port, { host: this.endpoint.url.hostname });
        } catch (e) {
            this.logger.warn(new Error('Unable to detect if server is reachable', { cause: e }));
            return;
        }

        try {
            const url = this.config.url;
            const resp = await request.get(`${url}/version`);
            this.logger.verbose(`Found Server version ${resp.body.version}`);
        } catch (e) {
            this.logger.warn(new Error('Server was reachable but could not determine version', { cause: e }));
        }
    }

    testAuth = async () => {
        this.authed = true;
        // TODO no easy way to test token is working without also pushing a message -- instead will de-auth if we get the right error message when trying to push for the first time
    }

    doNotify = async (payload: WebhookPayload) => {
        try {
            await gotify({
                server: this.endpoint.normal,
                app: this.config.token,
                message: payload.message,
                title: payload.title !== undefined ? `${payload.identifier} - ${payload.title}` : undefined,
                priority: this.priorities[payload.priority]
            });
            this.logger.verbose(`Pushed notification.`);
        } catch (e) {
            if(e instanceof HTTPError && e.response.statusCode === 401) {
                this.logger.warn(new Error(`Unable to push notification. Error returned with 401 which means the TOKEN provided is probably incorrect. Disabling Notifier \n Response Error => ${e.response.body}`, {cause: e}));
                this.authed = false;
            } else {
                this.logger.warn(new Error('Failed to push notification', {cause: e}));
            }
        }
    }
}
