import {IOGateway} from '@interopio/gateway';
import {GatewayServer} from '../../gateway-server';
import getLogger from '../logger.js';

const log = getLogger('gateway.ws.client-verify');

export type ProcessedOriginFilters
    = Required<Omit<GatewayServer.OriginFilters, 'blacklist' | 'whitelist'>>
    //| Required<Omit<GatewayServer.OriginFilters, 'block' | 'allow'>>
    ;

function acceptsMissing(originFilters: ProcessedOriginFilters): boolean {
    switch (originFilters.missing) {
        case 'allow': // fall-through
        case 'whitelist':
            return true;
        case 'block': // fall-through
        case 'blacklist':
            return false;
        default:
            return false;
    }
}

function tryMatch(originFilters: ProcessedOriginFilters, origin: string): boolean | undefined {
    const block = originFilters.block ?? originFilters['blacklist'];
    const allow = originFilters.allow ?? originFilters['whitelist'];
    if (block.length > 0 && IOGateway.Filtering.valuesMatch(block, origin)) {
        log.warn(`origin ${origin} matches block filter`);
        return false;
    } else if (allow.length > 0 && IOGateway.Filtering.valuesMatch(allow, origin)) {
        if (log.enabledFor('debug')) {
            log.debug(`origin ${origin} matches allow filter`);
        }
        return true;
    }
}

function acceptsNonMatched(originFilters: ProcessedOriginFilters): boolean {
    switch (originFilters.non_matched) {
        case 'allow': // fall-through
        case 'whitelist':
            return true;
        case 'block': // fall-through
        case 'blacklist':
            return false;
        default:
            return false;
    }
}

export function acceptsOrigin(origin?: string, originFilters?: ProcessedOriginFilters): boolean {
    if (!originFilters) {
        return true;
    }
    if (!origin) {
        return acceptsMissing(originFilters);
    } else {
        const matchResult: boolean | undefined = tryMatch(originFilters, origin);
        if (matchResult) {
            return matchResult;
        } else {
            return acceptsNonMatched(originFilters);
        }
    }
}

export function regexifyOriginFilters(originFilters?: GatewayServer.OriginFilters): ProcessedOriginFilters | undefined {
    if (originFilters) {
        const block = (originFilters.block ?? originFilters.blacklist ?? []).map(IOGateway.Filtering.regexify);
        const allow = (originFilters.allow ?? originFilters.whitelist ?? []).map(IOGateway.Filtering.regexify);
        return {
            non_matched: originFilters.non_matched ?? 'allow',
            missing: originFilters.missing ?? 'allow',
            allow,
            block,
        }
    }
}
