import { Request as ExpressRequest, Response as ExpressResponse } from "express";
import { Option, tryDo } from "@shared/common/async_utils";
import { rpcClient } from "src/utils/rpc";
import got from "got";
import { logger } from "src/utils/logging";
import { ENV } from "src/utils/environment";

export interface VerifyInfo {
    captchaSitekey: string;
    userVerified: boolean;
}

export interface VerifyRequest {
    captchaResponse: string;
}

interface HCaptchaResponse {
    success: boolean;
    "error-codes"?: string[];
}

const VERIFY_URL = "https://hcaptcha.com/siteverify";

type GetResult = Promise<ExpressResponse<VerifyInfo>>;
export const get = async (req: ExpressRequest, res: ExpressResponse): GetResult => {
    if (!req.session?.userId) {
        return res.json({
            captchaSitekey: ENV.HCAPTCHA_SITEKEY,
            userVerified: true,
        });
    }
    return res.json({
        captchaSitekey: ENV.HCAPTCHA_SITEKEY,
        userVerified: (await rpcClient.userVerified({ userId: req.session.userId })).verified,
    });
};

type PostResult = Promise<ExpressResponse<Option<unknown, { error: string }>>>;
export const post = async (req: ExpressRequest, res: ExpressResponse): PostResult => {
    const hasToken = (body: unknown):
        body is VerifyRequest => body instanceof Object
                                    && (body as VerifyRequest).captchaResponse !== undefined;
    if (!hasToken(req.body)) {
        return res.json({
            ok: false,
            error: "No user token provided, please try again",
        });
    }

    if (!req.session?.userId) {
        return res.json({
            ok: false,
            error: "Not logged in, please log in",
        });
    }

    const response = await tryDo(got<HCaptchaResponse>(VERIFY_URL, {
        method: "post",
        responseType: "json",
        form: {
            secret: ENV.HCAPTCHA_SECRET,
            response: req.body.captchaResponse,
        },
    }));

    if (!response.ok) {
        logger.error("Failed to hCaptcha user %s: %s", req.session.userId, response.error);
        return res.json({
            ok: false,
            error: "Failed to verify hCaptcha response. Please try again.",
        });
    }

    const captchaResponse = response.result.body;

    if (!captchaResponse.success) {
        const errors = captchaResponse["error-codes"] ?? [];
        logger.error("Failed hCaptcha verify on user %s. Got errors: %s", req.session.userId, errors.join(";"));
        return res.json({
            ok: false,
            error: "Failed to verify hCaptcha response. Please try again.",
        });
    }

    const verifyResponse = await rpcClient.verifyUser({ userId: req.session.userId });
    if (!verifyResponse.ok) {
        logger.error("Failed to verify user %s (%s)", req.session.userId, req.session.username);
        return res.json({
            ok: false,
            error: "Failed to verify your account. Please try again or contact server owners.",
        });
    }
    return res.json({
        ok: true,
    });
};
