import path from 'node:path';
import { Reader } from '@maxmind/geoip2-node';
import config from 'config';

import runtimeId from '../../utils/runtime-id.js';
import initLogger from '../logger.js';

const logger = initLogger();
const regions = config.restrictions.regions;

export default async function initRestrictionHandler() {
	const reader = await Reader.open('assets/GeoLite2-City.mmdb');

	function getRestriction(req) {
		if (req.session.geo
			&& Object.hasOwn(req.session.geo, 'country')
			&& req.session.geo.ip === req.userIp
			&& req.session.geo.runtimeId === runtimeId) {
			const { country, subdivision } = req.session.geo;

			if (!config.restrictions.enabled) {
				return {
					restriction: 0,
					country,
					subdivision,
				};
			}

			if (Object.hasOwn(req.session.geo, 'restriction')) {
				return {
					restriction: req.session.geo.restriction,
					country,
					subdivision,
				};
			}
		}

		const location = reader.city(req.userIp);
		const country = location.country.isoCode;
		const subdivision = location.subdivisions?.[0]?.isoCode;

		if (!config.restrictions.enabled) {
			return {
				restriction: 0,
				country,
				subdivision,
			};
		}

		if (regions[country]?.[subdivision]) {
			// state or province restriction
			return {
				restriction: config.restrictions.modes[regions[country][subdivision]],
				country,
				subdivision,
			};
		}

		if (regions[country]) {
			// country restriction
			return {
				restriction: config.restrictions.modes[regions[country]],
				country,
				subdivision,
			};
		}

		return {
			restriction: null,
			country,
			subdivision,
		};
	}

	function restrictionHandler(req, res, next) {
		try {
			const {
				restriction,
				country,
				subdivision,
			} = getRestriction(req);

			if (restriction === 'block' || req.path === '/sfw/') {
				res.render(path.join(import.meta.dirname, '../../assets/sfw.ejs'), {
					noVpn: config.restrictions.noVpn.includes(country),
				});

				return;
			}

			if (req.session.geo?.restriction !== restriction) {
				req.session.geo = {
					ip: req.userIp,
					runtimeId,
					restriction,
					country,
					subdivision,
				};
			}

			req.geo = {
				restriction,
				country,
				subdivision,
			};
		}
		catch (error) {
			logger.error(`Failed Maxmind IP lookup for ${req.ip}: ${error.message}`);

			req.session.geo = {
				ip: req.userIp,
				runtimeId,
				restriction: 0,
				country: null,
				subdivision: null,
			};

			req.geo = {
				restriction: 0,
				country: null,
				subdivision: null,
			};
		}

		next();
	}

	return restrictionHandler;
}
