'use strict';

const {Host} = require('../models/host');
const {SocketServerJson} = require('../utils/unix_socket_json');
const conf = require('@simpleworkjs/conf');

/**
 * Host Lookup Service
 *
 * Unix socket server that handles host/domain lookup requests from OpenResty.
 * This provides the bridge between nginx (Lua) and the Node.js host management system.
 *
 * Flow:
 * 1. OpenResty sends domain lookup request via Unix socket
 * 2. Service queries Host model (supports wildcards via lookup tree)
 * 3. Returns host configuration (IP, port, SSL settings, etc.)
 * 4. All values converted to strings for Redis compatibility
 *
 * Redis Compatibility:
 * All object values are converted to strings before sending because:
 * - Redis stores everything as strings
 * - OpenResty's primary lookup path uses Redis directly (hgetall)
 * - This socket is a fallback when Redis cache misses
 * - Both paths must return identical data structures to Lua consumer
 */

const socket = new SocketServerJson({
	socketFile: conf.socketFile,

	onData: function(data, clientSocket) {
		try{
			// Try to match the requested host name using the lookup tree
			let parentHost = Host.lookUp(data['domain']);

			// If we don't have a match, return empty object
			if(!parentHost) return clientSocket.write(JSON.stringify({}) + '\n');

			// lookUp returns the live #record object stored inside the shared
			// lookup tree. Everything below mutates parentHost (sets
			// wildcard_parent, stringifies every value), so work on a shallow
			// copy — mutating the shared node would corrupt the tree, e.g. turn
			// wildcard_matchAny into the string "false" (truthy) and break the
			// matchAny guard on subsequent lookups.
			parentHost = {...parentHost};

			// A wildcard host with matchAny disabled only serves subdomains that
			// are explicitly defined in redis. Reaching this service means redis
			// had no direct entry for the requested domain, so an inexact match
			// here (the request isn't the wildcard host itself) is an undefined
			// subdomain and must not be routed to the wildcard parent.
			if(parentHost.is_wildcard && !parentHost.wildcard_matchAny
					&& parentHost.host !== data['domain']){
				return clientSocket.write(JSON.stringify({}) + '\n');
			}

			// If the matched host belongs to a wildcard domain, set wildcard_parent
			// This allows child domains to use the parent's wildcard SSL certificate
			if(!parentHost.wildcard_parent){
				parentHost.wildcard_parent = parentHost.host;
				Host.addCache(data['domain'], parentHost);
			}

			// Convert all values to strings for Redis compatibility
			// OpenResty expects the same data format from both Redis and this socket
			for(const [key, value] of Object.entries(parentHost)) {
				parentHost[key] = String(value);
			}

			// Terminate with a newline: the Lua client (ops/nginx_conf/targetinfo.lua)
			// reads a single line per lookup via a cosocket receive() -- without a
			// delimiter it would block for the full read timeout on every request
			// waiting for a newline that never arrives (this was masked before by
			// blocking LuaSocket's timeout+partial-read behavior, which silently
			// paid that same timeout on every single lookup).
			clientSocket.write(JSON.stringify(parentHost) + '\n');
		}catch(error){
			console.error('services/host_lookup onData error', error);
		}
	},

	onListen: function(){
		console.log('Host lookup service listening on', conf.socketFile);
	}
});

module.exports = {socket};
